summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/Makefile.am10
-rw-r--r--runtime/glbl.c25
-rw-r--r--runtime/glbl.h1
-rw-r--r--runtime/netstrm.c374
-rw-r--r--runtime/netstrm.h14
-rw-r--r--runtime/nsd.h48
-rw-r--r--runtime/nsd_ptcp.c579
-rw-r--r--runtime/nsd_ptcp.h48
-rw-r--r--runtime/obj-types.h4
-rw-r--r--runtime/rsyslog.h3
-rw-r--r--tools/omfwd.c2
11 files changed, 779 insertions, 329 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 400d78c0..077310c6 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -11,6 +11,7 @@ librsyslog_la_SOURCES = \
syslogd-types.h \
module-template.h \
obj-types.h \
+ nsd.h \
glbl.h \
glbl.c \
msg.c \
@@ -94,4 +95,13 @@ lmnetstrm_la_SOURCES = netstrm.c netstrm.h
lmnetstrm_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
lmnetstrm_la_LDFLAGS = -module -avoid-version
lmnetstrm_la_LIBADD =
+
+# netstream drivers
+
+# plain tcp driver
+pkglib_LTLIBRARIES += lmnsd_ptcp.la
+lmnsd_ptcp_la_SOURCES = nsd_ptcp.c nsd_ptcp.h
+lmnsd_ptcp_la_CPPFLAGS = $(pthreads_cflags) $(rsrt_cflags)
+lmnsd_ptcp_la_LDFLAGS = -module -avoid-version
+lmnsd_ptcp_la_LIBADD =
endif # if ENABLE_INET
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 047fd611..1e51b0e0 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -38,6 +38,11 @@
#include "cfsysline.h"
#include "glbl.h"
+/* some defaults */
+#ifndef DFLT_NETSTRM_DRVR
+# define DFLT_NETSTRM_DRVR ((uchar*)"lmnsd_ptcp")
+#endif
+
/* static data */
DEFobjStaticHelpers
@@ -54,6 +59,7 @@ static uchar *LocalHostName = NULL;/* our hostname - read-only after startup */
static uchar *LocalDomain; /* our local domain name - read-only after startup */
static char **StripDomains = NULL;/* these domains may be stripped before writing logs - r/o after s.u., never touched by init */
static char **LocalHosts = NULL;/* these hosts are logged with their hostname - read-only after startup, never touched by init */
+static uchar *pszDfltNetstrmDrvr = NULL; /* module name of default netstream driver */
/* define a macro for the simple properties' set and get functions
@@ -84,6 +90,7 @@ SIMP_PROP(StripDomains, StripDomains, char**)
SIMP_PROP(LocalHosts, LocalHosts, char**)
SIMP_PROP_SET(LocalHostName, LocalHostName, uchar*)
+SIMP_PROP_SET(DfltNetstrmDrvr, pszDfltNetstrmDrvr, uchar*) // TODO: use custom function which frees existing value
#undef SIMP_PROP
#undef SIMP_PROP_SET
@@ -99,8 +106,7 @@ GetLocalHostName(void)
}
-/* return the current working directory.
- */
+/* return the current working directory */
static uchar*
GetWorkDir(void)
{
@@ -108,6 +114,14 @@ GetWorkDir(void)
}
+/* return the current default netstream driver */
+static uchar*
+GetDfltNetstrmDrvr(void)
+{
+ return(pszDfltNetstrmDrvr == NULL ? DFLT_NETSTRM_DRVR : pszWorkDir);
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-21
*/
@@ -134,6 +148,7 @@ CODESTARTobjQueryInterface(glbl)
SIMP_PROP(LocalDomain)
SIMP_PROP(StripDomains)
SIMP_PROP(LocalHosts)
+ SIMP_PROP(DfltNetstrmDrvr)
#undef SIMP_PROP
finalize_it:
ENDobjQueryInterface(glbl)
@@ -144,6 +159,10 @@ ENDobjQueryInterface(glbl)
*/
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
+ if(pszDfltNetstrmDrvr != NULL) {
+ free(pszDfltNetstrmDrvr);
+ pszDfltNetstrmDrvr = NULL;
+ }
if(pszWorkDir != NULL) {
free(pszWorkDir);
pszWorkDir = NULL;
@@ -172,6 +191,8 @@ ENDObjClassInit(glbl)
* rgerhards, 2008-04-17
*/
BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */
+ if(pszDfltNetstrmDrvr != NULL)
+ free(pszDfltNetstrmDrvr);
if(pszWorkDir != NULL)
free(pszWorkDir);
if(LocalHostName != NULL)
diff --git a/runtime/glbl.h b/runtime/glbl.h
index d61f9b41..b6864f3d 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -48,6 +48,7 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
SIMP_PROP(LocalDomain, uchar*)
SIMP_PROP(StripDomains, char**)
SIMP_PROP(LocalHosts, char**)
+ SIMP_PROP(DfltNetstrmDrvr, uchar*)
#undef SIMP_PROP
ENDinterface(glbl)
#define glblCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/netstrm.c b/runtime/netstrm.c
index c27d5f4d..274a92d7 100644
--- a/runtime/netstrm.c
+++ b/runtime/netstrm.c
@@ -60,6 +60,7 @@
#include "obj.h"
#include "errmsg.h"
#include "net.h"
+#include "nsd.h"
#include "netstrm.h"
MODULE_TYPE_LIB
@@ -71,172 +72,93 @@ DEFobjCurrIf(glbl)
DEFobjCurrIf(net)
-/* Standard-Constructor
- */
-BEGINobjConstruct(netstrm) /* be sure to specify the object type also in END macro! */
- pThis->sock = -1;
- pThis->iSessMax = 500; /* default max nbr of sessions -TODO:make configurable--rgerhards, 2008-04-17*/
-ENDobjConstruct(netstrm)
-
-
-/* ConstructionFinalizer
+/* load our low-level driver. This must be done before any
+ * driver-specific functions (allmost all...) can be carried
+ * out. Note that the driver's .ifIsLoaded is correctly
+ * initialized by calloc() and we depend on that.
+ * rgerhards, 2008-04-18
*/
static rsRetVal
-netstrmConstructFinalize(netstrm_t __attribute__((unused)) *pThis)
+loadDrvr(netstrm_t *pThis)
{
+ uchar *pDrvrName;
DEFiRet;
- ISOBJ_TYPE_assert(pThis, netstrm);
+
+ pDrvrName = pThis->pDrvrName;
+ if(pDrvrName == NULL) /* if no drvr name is set, use system default */
+ pDrvrName = glbl.GetDfltNetstrmDrvr();
+
+ pThis->Drvr.ifVersion = nsdCURR_IF_VERSION;
+ /* The pDrvrName+2 below is a hack to obtain the object name. It
+ * safes us to have yet another variable with the name without "lm" in
+ * front of it. If we change the module load interface, we may re-think
+ * about this hack, but for the time being it is efficient and clean
+ * enough. -- rgerhards, 2008-04-18
+ */
+ CHKiRet(obj.UseObj(__FILE__, pDrvrName+2, pDrvrName, (void*) &pThis->Drvr));
+finalize_it:
RETiRet;
}
+/* Standard-Constructor */
+BEGINobjConstruct(netstrm) /* be sure to specify the object type also in END macro! */
+ENDobjConstruct(netstrm)
+
+
/* destructor for the netstrm object */
BEGINobjDestruct(netstrm) /* be sure to specify the object type also in END and CODESTART macros! */
- int i;
CODESTARTobjDestruct(netstrm)
- if(pThis->sock != -1) {
- close(pThis->sock);
- pThis->sock = -1;
- }
-
- if(pThis->socks != NULL) {
- /* if we have some sockets at this stage, we need to close them */
- for(i = 1 ; i <= pThis->socks[0] ; ++i)
- close(pThis->socks[i]);
- free(pThis->socks);
- }
-
- if(pThis->pRemHostIP != NULL)
- free(pThis->pRemHostIP);
- if(pThis->pRemHostName != NULL)
- free(pThis->pRemHostName);
+ if(pThis->pDrvrData != NULL)
+ iRet = pThis->Drvr.Destruct(&pThis->pDrvrData);
ENDobjDestruct(netstrm)
-/* abort a connection. This is much like Destruct(), but tries
- * to discard any unsent data. -- rgerhards, 2008-03-24
- */
+/* ConstructionFinalizer */
static rsRetVal
-AbortDestruct(netstrm_t **ppThis)
+netstrmConstructFinalize(netstrm_t *pThis)
{
- struct linger ling;
-
DEFiRet;
- assert(ppThis != NULL);
- ISOBJ_TYPE_assert((*ppThis), netstrm);
-
- if((*ppThis)->sock != -1) {
- ling.l_onoff = 1;
- ling.l_linger = 0;
- if(setsockopt((*ppThis)->sock, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) < 0 ) {
- dbgprintf("could not set SO_LINGER, errno %d\n", errno);
- }
- }
-
- iRet = netstrmDestruct(ppThis);
-
+ ISOBJ_TYPE_assert(pThis, netstrm);
+ CHKiRet(loadDrvr(pThis));
+ CHKiRet(pThis->Drvr.Construct(&pThis->pDrvrData));
+finalize_it:
RETiRet;
}
-
-/* Set pRemHost based on the address provided. This is to be called upon accept()ing
- * a connection request. It must be provided by the socket we received the
- * message on as well as a NI_MAXHOST size large character buffer for the FQDN.
- * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats)
- * for some explanation of the code found below. If we detect a malicious
- * hostname, we return RS_RET_MALICIOUS_HNAME and let the caller decide
- * on how to deal with that.
- * rgerhards, 2008-03-31
+/* abort a connection. This is much like Destruct(), but tries
+ * to discard any unsent data. -- rgerhards, 2008-03-24
*/
static rsRetVal
-FillRemHost(netstrm_t *pThis, struct sockaddr *pAddr)
+AbortDestruct(netstrm_t **ppThis)
{
- int error;
- uchar szIP[NI_MAXHOST] = "";
- uchar szHname[NI_MAXHOST] = "";
- struct addrinfo hints, *res;
- size_t len;
-
DEFiRet;
- ISOBJ_TYPE_assert(pThis, netstrm);
- assert(pAddr != NULL);
-
- error = getnameinfo(pAddr, SALEN(pAddr), (char*)szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST);
-
- if(error) {
- dbgprintf("Malformed from address %s\n", gai_strerror(error));
- strcpy((char*)szHname, "???");
- strcpy((char*)szIP, "???");
- ABORT_FINALIZE(RS_RET_INVALID_HNAME);
- }
-
- if(!glbl.GetDisableDNS()) {
- error = getnameinfo(pAddr, SALEN(pAddr), (char*)szHname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
- if(error == 0) {
- memset (&hints, 0, sizeof (struct addrinfo));
- hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
- /* 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((char*)szHname, NULL, &hints, &res) == 0) {
- freeaddrinfo (res);
- /* OK, we know we have evil, so let's indicate this to our caller */
- snprintf((char*)szHname, NI_MAXHOST, "[MALICIOUS:IP=%s]", szIP);
- dbgprintf("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname);
- iRet = RS_RET_MALICIOUS_HNAME;
- }
- } else {
- strcpy((char*)szHname, (char*)szIP);
- }
- } else {
- strcpy((char*)szHname, (char*)szIP);
- }
+ assert(ppThis != NULL);
+ ISOBJ_TYPE_assert((*ppThis), netstrm);
- /* We now have the names, so now let's allocate memory and store them permanently.
- * (side note: we may hold on to these values for quite a while, thus we trim their
- * memory consumption)
- */
- len = strlen((char*)szIP) + 1; /* +1 for \0 byte */
- if((pThis->pRemHostIP = malloc(len)) == NULL)
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- memcpy(pThis->pRemHostIP, szIP, len);
-
- len = strlen((char*)szHname) + 1; /* +1 for \0 byte */
- if((pThis->pRemHostName = malloc(len)) == NULL) {
- free(pThis->pRemHostIP); /* prevent leak */
- pThis->pRemHostIP = NULL;
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- }
- memcpy(pThis->pRemHostName, szHname, len);
+ /* we do NOT exit on error, because that would make things worse */
+ (*ppThis)->Drvr.Abort((*ppThis)->pDrvrData);
+ iRet = netstrmDestruct(ppThis);
-finalize_it:
RETiRet;
}
+#if 0
+This is not yet working - wait until we arrive at the receiver side (distracts too much at the moment)
-/* accept an incoming connection request, sock provides the socket on which we can
+/* accept an incoming connection request, pNsdLstn provides the "listen socket" on which we can
* accept the new session.
* rgerhards, 2008-03-17
*/
static rsRetVal
-AcceptConnReq(netstrm_t **ppThis, int sock)
+AcceptConnReq(netstrm_t **ppThis, nsd_t *pNsdLstn)
{
netstrm_t *pThis = NULL;
- int sockflags;
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof(addr);
- int iNewSock = -1;
-
+ nsd_t *pNsd;
DEFiRet;
- assert(ppThis != NULL);
- iNewSock = accept(sock, (struct sockaddr*) &addr, &addrlen);
- if(iNewSock < 0) {
- ABORT_FINALIZE(RS_RET_ACCEPT_ERR);
- }
+ assert(ppThis != NULL);
/* construct our object so that we can use it... */
CHKiRet(netstrmConstruct(&pThis));
@@ -272,6 +194,7 @@ finalize_it:
RETiRet;
}
+#endif
/* initialize the tcp socket for a listner
@@ -284,144 +207,10 @@ finalize_it:
static rsRetVal
LstnInit(netstrm_t *pThis, uchar *pLstnPort)
{
- struct addrinfo hints, *res, *r;
- int error, maxs, *s, on = 1;
- int sockflags;
-
DEFiRet;
ISOBJ_TYPE_assert(pThis, netstrm);
assert(pLstnPort != NULL);
-
- dbgprintf("creating tcp listen socket on port %s\n", pLstnPort);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_PASSIVE;
- hints.ai_family = glbl.GetDefPFFamily();
- hints.ai_socktype = SOCK_STREAM;
-
- error = getaddrinfo(NULL, (char*) pLstnPort, &hints, &res);
- if(error) {
- dbgprintf("error %d querying port '%s'\n", error, pLstnPort);
- ABORT_FINALIZE(RS_RET_INVALID_PORT);
- }
-
- /* Count max number of sockets we may open */
- for(maxs = 0, r = res; r != NULL ; r = r->ai_next, maxs++)
- /* EMPTY */;
- pThis->socks = malloc((maxs+1) * sizeof(int));
- if (pThis->socks == NULL) {
- dbgprintf("couldn't allocate memory for TCP listen sockets, suspending RELP message reception.");
- freeaddrinfo(res);
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- }
-
- *pThis->socks = 0; /* num of sockets counter at start of array */
- s = pThis->socks + 1;
- for(r = res; r != NULL ; r = r->ai_next) {
- *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
- if (*s < 0) {
- if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT))
- dbgprintf("creating tcp listen socket");
- /* it is debatable if PF_INET with EAFNOSUPPORT should
- * also be ignored...
- */
- continue;
- }
-
-#ifdef IPV6_V6ONLY
- if (r->ai_family == AF_INET6) {
- int iOn = 1;
- if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
- (char *)&iOn, sizeof (iOn)) < 0) {
- close(*s);
- *s = -1;
- continue;
- }
- }
-#endif
- if(setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) {
- dbgprintf("error %d setting tcp socket option\n", errno);
- close(*s);
- *s = -1;
- continue;
- }
-
- /* We use non-blocking IO! */
- if((sockflags = fcntl(*s, F_GETFL)) != -1) {
- sockflags |= O_NONBLOCK;
- /* SETFL could fail too, so get it caught by the subsequent
- * error check.
- */
- sockflags = fcntl(*s, F_SETFL, sockflags);
- }
- if(sockflags == -1) {
- dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket", errno);
- close(*s);
- *s = -1;
- continue;
- }
-
-
-
- /* We need to enable BSD compatibility. Otherwise an attacker
- * could flood our log files by sending us tons of ICMP errors.
- */
-#ifndef BSD
- if(net.should_use_so_bsdcompat()) {
- if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
- (char *) &on, sizeof(on)) < 0) {
- errmsg.LogError(NO_ERRCODE, "TCP setsockopt(BSDCOMPAT)");
- close(*s);
- *s = -1;
- continue;
- }
- }
-#endif
-
- if( (bind(*s, r->ai_addr, r->ai_addrlen) < 0)
-#ifndef IPV6_V6ONLY
- && (errno != EADDRINUSE)
-#endif
- ) {
- dbgprintf("error %d while binding tcp socket", errno);
- close(*s);
- *s = -1;
- continue;
- }
-
- if(listen(*s,pThis->iSessMax / 10 + 5) < 0) {
- /* If the listen fails, it most probably fails because we ask
- * for a too-large backlog. So in this case we first set back
- * to a fixed, reasonable, limit that should work. Only if
- * that fails, too, we give up.
- */
- dbgprintf("listen with a backlog of %d failed - retrying with default of 32.",
- pThis->iSessMax / 10 + 5);
- if(listen(*s, 32) < 0) {
- dbgprintf("tcp listen error %d, suspending\n", errno);
- close(*s);
- *s = -1;
- continue;
- }
- }
-
- (*pThis->socks)++;
- s++;
- }
-
- if(res != NULL)
- freeaddrinfo(res);
-
- if(*pThis->socks != maxs)
- dbgprintf("We could initialize %d RELP TCP listen sockets out of %d we received "
- "- this may or may not be an error indication.\n", *pThis->socks, maxs);
-
- if(*pThis->socks == 0) {
- dbgprintf("No RELP TCP listen socket could successfully be initialized, "
- "message reception via RELP disabled.\n");
- free(pThis->socks);
- ABORT_FINALIZE(RS_RET_COULD_NOT_BIND);
- }
+ CHKiRet(pThis->Drvr.LstnInit(pThis->pDrvrData, pLstnPort));
finalize_it:
RETiRet;
@@ -438,13 +227,11 @@ finalize_it:
* rgerhards, 2008-03-17
*/
static rsRetVal
-Rcv(netstrm_t *pThis, uchar *pRcvBuf, ssize_t *pLenBuf)
+Rcv(netstrm_t *pThis, uchar *pBuf, ssize_t *pLenBuf)
{
DEFiRet;
ISOBJ_TYPE_assert(pThis, netstrm);
-
- *pLenBuf = recv(pThis->sock, pRcvBuf, *pLenBuf, MSG_DONTWAIT);
-
+ iRet = pThis->Drvr.Rcv(pThis->pDrvrData, pBuf, pLenBuf);
RETiRet;
}
@@ -458,27 +245,9 @@ Rcv(netstrm_t *pThis, uchar *pRcvBuf, ssize_t *pLenBuf)
static rsRetVal
Send(netstrm_t *pThis, uchar *pBuf, ssize_t *pLenBuf)
{
- ssize_t written;
DEFiRet;
ISOBJ_TYPE_assert(pThis, netstrm);
-
- written = send(pThis->sock, pBuf, *pLenBuf, 0);
-
- if(written == -1) {
- switch(errno) {
- case EAGAIN:
- case EINTR:
- /* this is fine, just retry... */
- written = 0;
- break;
- default:
- ABORT_FINALIZE(RS_RET_IO_ERROR);
- break;
- }
- }
-
- *pLenBuf = written;
-finalize_it:
+ iRet = pThis->Drvr.Send(pThis->pDrvrData, pBuf, pLenBuf);
RETiRet;
}
@@ -489,42 +258,11 @@ finalize_it:
static rsRetVal
Connect(netstrm_t *pThis, int family, uchar *port, uchar *host)
{
- struct addrinfo *res = NULL;
- struct addrinfo hints;
-
DEFiRet;
ISOBJ_TYPE_assert(pThis, netstrm);
assert(port != NULL);
assert(host != NULL);
- assert(pThis->sock == -1);
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = family;
- hints.ai_socktype = SOCK_STREAM;
- if(getaddrinfo((char*)host, (char*)port, &hints, &res) != 0) {
- dbgprintf("error %d in getaddrinfo\n", errno);
- ABORT_FINALIZE(RS_RET_IO_ERROR);
- }
-
- if((pThis->sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
- ABORT_FINALIZE(RS_RET_IO_ERROR);
- }
-
- if(connect(pThis->sock, res->ai_addr, res->ai_addrlen) != 0) {
- ABORT_FINALIZE(RS_RET_IO_ERROR);
- }
-
-finalize_it:
- if(res != NULL)
- freeaddrinfo(res);
-
- if(iRet != RS_RET_OK) {
- if(pThis->sock != -1) {
- close(pThis->sock);
- pThis->sock = -1;
- }
- }
-
+ iRet = pThis->Drvr.Connect(pThis->pDrvrData, family, port, host);
RETiRet;
}
@@ -547,7 +285,7 @@ CODESTARTobjQueryInterface(netstrm)
pIf->Destruct = netstrmDestruct;
pIf->AbortDestruct = AbortDestruct;
pIf->LstnInit = LstnInit;
- pIf->AcceptConnReq = AcceptConnReq;
+ // TODO: add later: pIf->AcceptConnReq = AcceptConnReq;
pIf->Rcv = Rcv;
pIf->Send = Send;
pIf->Connect = Connect;
diff --git a/runtime/netstrm.h b/runtime/netstrm.h
index 7f267a36..75b7c457 100644
--- a/runtime/netstrm.h
+++ b/runtime/netstrm.h
@@ -24,21 +24,21 @@
#ifndef INCLUDED_NETSTRM_H
#define INCLUDED_NETSTRM_H
+#include "nsd.h" /* we need our driver interface to be defined */
+
/* the netstrm object */
struct netstrm_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
- uchar *pRemHostIP; /**< IP address of remote peer (currently used in server mode, only) */
- uchar *pRemHostName; /**< host name of remote peer (currently used in server mode, only) */
- int sock; /**< the socket we use for regular, single-socket, operations */
- int *socks; /**< the socket(s) we use for listeners, element 0 has nbr of socks */
- int iSessMax; /**< maximum number of sessions permitted */
+ nsd_if_t Drvr; /**< our stream driver */
+ nsd_t *pDrvrData; /**< the driver's data elements */
+ uchar *pDrvrName; /**< nsd driver name to use, or NULL if system default */
};
-/* interfaces */
+/* interface */
BEGINinterface(netstrm) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Construct)(netstrm_t **ppThis);
- rsRetVal (*ConstructFinalize)(netstrm_t __attribute__((unused)) *pThis);
+ rsRetVal (*ConstructFinalize)(netstrm_t *pThis);
rsRetVal (*Destruct)(netstrm_t **ppThis);
rsRetVal (*AbortDestruct)(netstrm_t **ppThis);
rsRetVal (*LstnInit)(netstrm_t *pThis, unsigned char *pLstnPort);
diff --git a/runtime/nsd.h b/runtime/nsd.h
new file mode 100644
index 00000000..52c36dcf
--- /dev/null
+++ b/runtime/nsd.h
@@ -0,0 +1,48 @@
+/* The interface definition for "NetStream Drivers" (nsd).
+ *
+ * This is just an abstract driver interface, which needs to be
+ * implemented by concrete classes. As such, no nsd data type itself
+ * is defined.
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+
+#ifndef INCLUDED_NSD_H
+#define INCLUDED_NSD_H
+
+/* nsd_t is actually obj_t (which is somewhat better than void* but in essence
+ * much the same).
+ */
+
+/* interface */
+BEGINinterface(nsd) /* name must also be changed in ENDinterface macro! */
+ rsRetVal (*Construct)(nsd_t **ppThis);
+ rsRetVal (*Destruct)(nsd_t **ppThis);
+ rsRetVal (*Abort)(nsd_t *pThis);
+ rsRetVal (*LstnInit)(nsd_t *pThis, unsigned char *pLstnPort);
+ rsRetVal (*AcceptConnReq)(nsd_t **ppThis, int sock);
+ rsRetVal (*Rcv)(nsd_t *pThis, uchar *pRcvBuf, ssize_t *pLenBuf);
+ rsRetVal (*Send)(nsd_t *pThis, uchar *pBuf, ssize_t *pLenBuf);
+ rsRetVal (*Connect)(nsd_t *pThis, int family, unsigned char *port, unsigned char *host);
+ENDinterface(nsd)
+#define nsdCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+#endif /* #ifndef INCLUDED_NSD_H */
diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c
new file mode 100644
index 00000000..98de5802
--- /dev/null
+++ b/runtime/nsd_ptcp.c
@@ -0,0 +1,579 @@
+/* nsd_ptcp.c
+ *
+ * An implementation of the nsd interface for plain tcp sockets.
+ *
+ * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+#include "config.h"
+
+#include "rsyslog.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <fnmatch.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "syslogd-types.h"
+#include "module-template.h"
+#include "parse.h"
+#include "srUtils.h"
+#include "obj.h"
+#include "errmsg.h"
+#include "net.h"
+#include "nsd_ptcp.h"
+
+MODULE_TYPE_LIB
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(net)
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(nsd_ptcp) /* be sure to specify the object type also in END macro! */
+ pThis->sock = -1;
+ pThis->iSessMax = 500; /* default max nbr of sessions -TODO:make configurable--rgerhards, 2008-04-17*/
+ENDobjConstruct(nsd_ptcp)
+
+
+/* destructor for the nsd_ptcp object */
+BEGINobjDestruct(nsd_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */
+ int i;
+CODESTARTobjDestruct(nsd_pctp)
+ if(pThis->sock != -1) {
+ close(pThis->sock);
+ pThis->sock = -1;
+ }
+
+ if(pThis->socks != NULL) {
+ /* if we have some sockets at this stage, we need to close them */
+ for(i = 1 ; i <= pThis->socks[0] ; ++i)
+ close(pThis->socks[i]);
+ free(pThis->socks);
+ }
+
+ if(pThis->pRemHostIP != NULL)
+ free(pThis->pRemHostIP);
+ if(pThis->pRemHostName != NULL)
+ free(pThis->pRemHostName);
+ENDobjDestruct(nsd_ptcp)
+
+
+/* abort a connection. This is meant to be called immediately
+ * before the Destruct call. -- rgerhards, 2008-03-24
+ */
+static rsRetVal
+Abort(nsd_t *pNsd)
+{
+ struct linger ling;
+ nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
+
+ DEFiRet;
+ ISOBJ_TYPE_assert((pThis), nsd_ptcp);
+
+ if((pThis)->sock != -1) {
+ ling.l_onoff = 1;
+ ling.l_linger = 0;
+ if(setsockopt((pThis)->sock, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) < 0 ) {
+ dbgprintf("could not set SO_LINGER, errno %d\n", errno);
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* Set pRemHost based on the address provided. This is to be called upon accept()ing
+ * a connection request. It must be provided by the socket we received the
+ * message on as well as a NI_MAXHOST size large character buffer for the FQDN.
+ * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats)
+ * for some explanation of the code found below. If we detect a malicious
+ * hostname, we return RS_RET_MALICIOUS_HNAME and let the caller decide
+ * on how to deal with that.
+ * rgerhards, 2008-03-31
+ */
+static rsRetVal
+FillRemHost(nsd_ptcp_t *pThis, struct sockaddr *pAddr)
+{
+ int error;
+ uchar szIP[NI_MAXHOST] = "";
+ uchar szHname[NI_MAXHOST] = "";
+ struct addrinfo hints, *res;
+ size_t len;
+
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nsd_ptcp);
+ assert(pAddr != NULL);
+
+ error = getnameinfo(pAddr, SALEN(pAddr), (char*)szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST);
+
+ if(error) {
+ dbgprintf("Malformed from address %s\n", gai_strerror(error));
+ strcpy((char*)szHname, "???");
+ strcpy((char*)szIP, "???");
+ ABORT_FINALIZE(RS_RET_INVALID_HNAME);
+ }
+
+ if(!glbl.GetDisableDNS()) {
+ error = getnameinfo(pAddr, SALEN(pAddr), (char*)szHname, NI_MAXHOST, NULL, 0, NI_NAMEREQD);
+ if(error == 0) {
+ memset (&hints, 0, sizeof (struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_socktype = SOCK_STREAM;
+ /* 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((char*)szHname, NULL, &hints, &res) == 0) {
+ freeaddrinfo (res);
+ /* OK, we know we have evil, so let's indicate this to our caller */
+ snprintf((char*)szHname, NI_MAXHOST, "[MALICIOUS:IP=%s]", szIP);
+ dbgprintf("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname);
+ iRet = RS_RET_MALICIOUS_HNAME;
+ }
+ } else {
+ strcpy((char*)szHname, (char*)szIP);
+ }
+ } else {
+ strcpy((char*)szHname, (char*)szIP);
+ }
+
+ /* We now have the names, so now let's allocate memory and store them permanently.
+ * (side note: we may hold on to these values for quite a while, thus we trim their
+ * memory consumption)
+ */
+ len = strlen((char*)szIP) + 1; /* +1 for \0 byte */
+ if((pThis->pRemHostIP = malloc(len)) == NULL)
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ memcpy(pThis->pRemHostIP, szIP, len);
+
+ len = strlen((char*)szHname) + 1; /* +1 for \0 byte */
+ if((pThis->pRemHostName = malloc(len)) == NULL) {
+ free(pThis->pRemHostIP); /* prevent leak */
+ pThis->pRemHostIP = NULL;
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+ memcpy(pThis->pRemHostName, szHname, len);
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+/* accept an incoming connection request, sock provides the socket on which we can
+ * accept the new session.
+ * rgerhards, 2008-03-17
+ */
+static rsRetVal
+AcceptConnReq(nsd_t **ppThis, int sock)
+{
+ int sockflags;
+ struct sockaddr_storage addr;
+ socklen_t addrlen = sizeof(addr);
+ nsd_ptcp_t *pThis = NULL;
+ int iNewSock = -1;
+
+ DEFiRet;
+ assert(ppThis != NULL);
+
+ iNewSock = accept(sock, (struct sockaddr*) &addr, &addrlen);
+ if(iNewSock < 0) {
+ ABORT_FINALIZE(RS_RET_ACCEPT_ERR);
+ }
+
+ /* construct our object so that we can use it... */
+ CHKiRet(nsd_ptcpConstruct(&pThis));
+
+ CHKiRet(FillRemHost(pThis, (struct sockaddr*) &addr));
+
+ /* set the new socket to non-blocking IO */
+ if((sockflags = fcntl(iNewSock, F_GETFL)) != -1) {
+ sockflags |= O_NONBLOCK;
+ /* SETFL could fail too, so get it caught by the subsequent
+ * error check.
+ */
+ sockflags = fcntl(iNewSock, F_SETFL, sockflags);
+ }
+ if(sockflags == -1) {
+ dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket %d", errno, iNewSock);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ pThis->sock = iNewSock;
+
+ *ppThis = (nsd_t*) pThis;
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ if(pThis != NULL)
+ nsd_ptcpDestruct(&pThis);
+ /* the close may be redundant, but that doesn't hurt... */
+ if(iNewSock >= 0)
+ close(iNewSock);
+ }
+
+ RETiRet;
+}
+
+
+/* initialize the tcp socket for a listner
+ * pLstnPort must point to a port name or number. NULL is NOT permitted
+ * (hint: we need to be careful when we use this module together with librelp,
+ * there NULL indicates the default port
+ * default is used.
+ * gerhards, 2008-03-17
+ */
+static rsRetVal
+LstnInit(nsd_t *pNsd, uchar *pLstnPort)
+{
+ nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
+ struct addrinfo hints, *res, *r;
+ int error, maxs, *s, on = 1;
+ int sockflags;
+
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nsd_ptcp);
+ assert(pLstnPort != NULL);
+
+ dbgprintf("creating tcp listen socket on port %s\n", pLstnPort);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = glbl.GetDefPFFamily();
+ hints.ai_socktype = SOCK_STREAM;
+
+ error = getaddrinfo(NULL, (char*) pLstnPort, &hints, &res);
+ if(error) {
+ dbgprintf("error %d querying port '%s'\n", error, pLstnPort);
+ ABORT_FINALIZE(RS_RET_INVALID_PORT);
+ }
+
+ /* Count max number of sockets we may open */
+ for(maxs = 0, r = res; r != NULL ; r = r->ai_next, maxs++)
+ /* EMPTY */;
+ pThis->socks = malloc((maxs+1) * sizeof(int));
+ if (pThis->socks == NULL) {
+ dbgprintf("couldn't allocate memory for TCP listen sockets, suspending RELP message reception.");
+ freeaddrinfo(res);
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+
+ *pThis->socks = 0; /* num of sockets counter at start of array */
+ s = pThis->socks + 1;
+ for(r = res; r != NULL ; r = r->ai_next) {
+ *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if (*s < 0) {
+ if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT))
+ dbgprintf("creating tcp listen socket");
+ /* it is debatable if PF_INET with EAFNOSUPPORT should
+ * also be ignored...
+ */
+ continue;
+ }
+
+#ifdef IPV6_V6ONLY
+ if (r->ai_family == AF_INET6) {
+ int iOn = 1;
+ if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *)&iOn, sizeof (iOn)) < 0) {
+ close(*s);
+ *s = -1;
+ continue;
+ }
+ }
+#endif
+ if(setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) {
+ dbgprintf("error %d setting tcp socket option\n", errno);
+ close(*s);
+ *s = -1;
+ continue;
+ }
+
+ /* We use non-blocking IO! */
+ if((sockflags = fcntl(*s, F_GETFL)) != -1) {
+ sockflags |= O_NONBLOCK;
+ /* SETFL could fail too, so get it caught by the subsequent
+ * error check.
+ */
+ sockflags = fcntl(*s, F_SETFL, sockflags);
+ }
+ if(sockflags == -1) {
+ dbgprintf("error %d setting fcntl(O_NONBLOCK) on tcp socket", errno);
+ close(*s);
+ *s = -1;
+ continue;
+ }
+
+
+
+ /* We need to enable BSD compatibility. Otherwise an attacker
+ * could flood our log files by sending us tons of ICMP errors.
+ */
+#ifndef BSD
+ if(net.should_use_so_bsdcompat()) {
+ if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
+ (char *) &on, sizeof(on)) < 0) {
+ errmsg.LogError(NO_ERRCODE, "TCP setsockopt(BSDCOMPAT)");
+ close(*s);
+ *s = -1;
+ continue;
+ }
+ }
+#endif
+
+ if( (bind(*s, r->ai_addr, r->ai_addrlen) < 0)
+#ifndef IPV6_V6ONLY
+ && (errno != EADDRINUSE)
+#endif
+ ) {
+ dbgprintf("error %d while binding tcp socket", errno);
+ close(*s);
+ *s = -1;
+ continue;
+ }
+
+ if(listen(*s,pThis->iSessMax / 10 + 5) < 0) {
+ /* If the listen fails, it most probably fails because we ask
+ * for a too-large backlog. So in this case we first set back
+ * to a fixed, reasonable, limit that should work. Only if
+ * that fails, too, we give up.
+ */
+ dbgprintf("listen with a backlog of %d failed - retrying with default of 32.",
+ pThis->iSessMax / 10 + 5);
+ if(listen(*s, 32) < 0) {
+ dbgprintf("tcp listen error %d, suspending\n", errno);
+ close(*s);
+ *s = -1;
+ continue;
+ }
+ }
+
+ (*pThis->socks)++;
+ s++;
+ }
+
+ if(res != NULL)
+ freeaddrinfo(res);
+
+ if(*pThis->socks != maxs)
+ dbgprintf("We could initialize %d RELP TCP listen sockets out of %d we received "
+ "- this may or may not be an error indication.\n", *pThis->socks, maxs);
+
+ if(*pThis->socks == 0) {
+ dbgprintf("No RELP TCP listen socket could successfully be initialized, "
+ "message reception via RELP disabled.\n");
+ free(pThis->socks);
+ ABORT_FINALIZE(RS_RET_COULD_NOT_BIND);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* receive data from a tcp socket
+ * The lenBuf parameter must contain the max buffer size on entry and contains
+ * the number of octets read (or -1 in case of error) on exit. This function
+ * never blocks, not even when called on a blocking socket. That is important
+ * for client sockets, which are set to block during send, but should not
+ * block when trying to read data. If *pLenBuf is -1, an error occured and
+ * errno holds the exact error cause.
+ * rgerhards, 2008-03-17
+ */
+static rsRetVal
+Rcv(nsd_t *pNsd, uchar *pRcvBuf, ssize_t *pLenBuf)
+{
+ DEFiRet;
+ nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
+ ISOBJ_TYPE_assert(pThis, nsd_ptcp);
+
+ *pLenBuf = recv(pThis->sock, pRcvBuf, *pLenBuf, MSG_DONTWAIT);
+
+ RETiRet;
+}
+
+
+/* send a buffer. On entry, pLenBuf contains the number of octets to
+ * write. On exit, it contains the number of octets actually written.
+ * If this number is lower than on entry, only a partial buffer has
+ * been written.
+ * rgerhards, 2008-03-19
+ */
+static rsRetVal
+Send(nsd_t *pNsd, uchar *pBuf, ssize_t *pLenBuf)
+{
+ nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
+ ssize_t written;
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nsd_ptcp);
+
+ written = send(pThis->sock, pBuf, *pLenBuf, 0);
+
+ if(written == -1) {
+ switch(errno) {
+ case EAGAIN:
+ case EINTR:
+ /* this is fine, just retry... */
+ written = 0;
+ break;
+ default:
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ break;
+ }
+ }
+
+ *pLenBuf = written;
+finalize_it:
+ RETiRet;
+}
+
+
+/* open a connection to a remote host (server).
+ * rgerhards, 2008-03-19
+ */
+static rsRetVal
+Connect(nsd_t *pNsd, int family, uchar *port, uchar *host)
+{
+ nsd_ptcp_t *pThis = (nsd_ptcp_t*) pNsd;
+ struct addrinfo *res = NULL;
+ struct addrinfo hints;
+
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, nsd_ptcp);
+ assert(port != NULL);
+ assert(host != NULL);
+ assert(pThis->sock == -1);
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ if(getaddrinfo((char*)host, (char*)port, &hints, &res) != 0) {
+ dbgprintf("error %d in getaddrinfo\n", errno);
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if((pThis->sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1) {
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+ if(connect(pThis->sock, res->ai_addr, res->ai_addrlen) != 0) {
+ ABORT_FINALIZE(RS_RET_IO_ERROR);
+ }
+
+finalize_it:
+ if(res != NULL)
+ freeaddrinfo(res);
+
+ if(iRet != RS_RET_OK) {
+ if(pThis->sock != -1) {
+ close(pThis->sock);
+ pThis->sock = -1;
+ }
+ }
+
+ RETiRet;
+}
+
+
+/* queryInterface function */
+BEGINobjQueryInterface(nsd_ptcp)
+CODESTARTobjQueryInterface(nsd_ptcp)
+ if(pIf->ifVersion != nsdCURR_IF_VERSION) {/* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->Construct = (rsRetVal(*)(nsd_t**)) nsd_ptcpConstruct;
+ pIf->Destruct = (rsRetVal(*)(nsd_t**)) nsd_ptcpDestruct;
+ pIf->Abort = Abort;
+ pIf->LstnInit = LstnInit;
+ pIf->AcceptConnReq = AcceptConnReq;
+ pIf->Rcv = Rcv;
+ pIf->Send = Send;
+ pIf->Connect = Connect;
+finalize_it:
+ENDobjQueryInterface(nsd_ptcp)
+
+
+/* exit our class
+ */
+BEGINObjClassExit(nsd_ptcp, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
+CODESTARTObjClassExit(nsd_ptcp)
+ /* release objects we no longer need */
+ objRelease(net, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ENDObjClassExit(nsd_ptcp)
+
+
+/* Initialize the nsd_ptcp class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+BEGINObjClassInit(nsd_ptcp, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(net, CORE_COMPONENT));
+
+ /* set our own handlers */
+ENDObjClassInit(nsd_ptcp)
+
+
+/* --------------- here now comes the plumbing that makes as a library module --------------- */
+
+
+BEGINmodExit
+CODESTARTmodExit
+ nsd_ptcpClassExit();
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_LIB_QUERIES
+ENDqueryEtryPt
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+
+ /* Initialize all classes that are in our module - this includes ourselfs */
+ CHKiRet(nsd_ptcpClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
+ENDmodInit
+/* vi:set ai:
+ */
diff --git a/runtime/nsd_ptcp.h b/runtime/nsd_ptcp.h
new file mode 100644
index 00000000..d4848314
--- /dev/null
+++ b/runtime/nsd_ptcp.h
@@ -0,0 +1,48 @@
+/* An implementation of the nsd interface for plain tcp sockets.
+ *
+ * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution.
+ */
+
+#ifndef INCLUDED_NSD_PTCP_H
+#define INCLUDED_NSD_PTCP_H
+
+#include "nsd.h"
+typedef nsd_if_t nsd_ptcp_if_t; /* we just *implement* this interface */
+
+/* the nsd_ptcp object */
+struct nsd_ptcp_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ uchar *pRemHostIP; /**< IP address of remote peer (currently used in server mode, only) */
+ uchar *pRemHostName; /**< host name of remote peer (currently used in server mode, only) */
+ int sock; /**< the socket we use for regular, single-socket, operations */
+ int *socks; /**< the socket(s) we use for listeners, element 0 has nbr of socks */
+ int iSessMax; /**< maximum number of sessions permitted */
+};
+
+/* interface is defined in nsd.h, we just implement it! */
+
+/* prototypes */
+PROTOTYPEObj(nsd_ptcp);
+
+/* the name of our library binary */
+#define LM_NSD_PTCP_FILENAME "lmnsd_ptcp"
+
+#endif /* #ifndef INCLUDED_NSD_PTCP_H */
diff --git a/runtime/obj-types.h b/runtime/obj-types.h
index e245b633..e3df7239 100644
--- a/runtime/obj-types.h
+++ b/runtime/obj-types.h
@@ -81,13 +81,13 @@ struct objInfo_s {
};
-typedef struct obj { /* the dummy struct that each derived class can be casted to */
+struct obj_s { /* the dummy struct that each derived class can be casted to */
objInfo_t *pObjInfo;
#ifndef NDEBUG /* this means if debug... */
unsigned int iObjCooCKiE; /* must always be 0xBADEFEE for a valid object */
#endif
uchar *pszName; /* the name of *this* specific object instance */
-} obj_t;
+};
/* macros which must be gloablly-visible (because they are used during definition of
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 7ed989c5..f7824006 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -61,9 +61,12 @@
/* define some base data types */
typedef unsigned char uchar;/* get rid of the unhandy "unsigned char" */
typedef struct thrdInfo thrdInfo_t;
+typedef struct obj_s obj_t;
typedef struct filed selector_t;/* TODO: this so far resides in syslogd.c, think about modularization */
typedef struct NetAddr netAddr_t;
typedef struct netstrm_s netstrm_t;
+typedef struct nsd_ptcp_s nsd_ptcp_t;
+typedef obj_t nsd_t;
typedef struct msg msg_t;
typedef struct interface_s interface_t;
typedef struct objInfo_s objInfo_t;
diff --git a/tools/omfwd.c b/tools/omfwd.c
index e7b5dcd7..3a2fe37f 100644
--- a/tools/omfwd.c
+++ b/tools/omfwd.c
@@ -253,6 +253,8 @@ static rsRetVal TCPSendInit(void *pvData)
assert(pData != NULL);
if(pData->pNetstrm == NULL) {
CHKiRet(netstrm.Construct(&pData->pNetstrm));
+ /* here we may set another netstream driver (e.g. to do TLS) */
+ CHKiRet(netstrm.ConstructFinalize(pData->pNetstrm));
CHKiRet(netstrm.Connect(pData->pNetstrm, glbl.GetDefPFFamily(),
(uchar*)pData->port, (uchar*)pData->f_hname));
}