From ffd0a1248e313c84ba486727a344b23ced2ce29d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Dec 2012 14:32:58 +0100 Subject: omudpspoof: add support for packets larger than 1472 bytes On Ethernet, they need to be transmitted in multiple fragments. While it is known that fragmentation can cause issues, it is the best choice to be made in that case. Also improved debug output. --- ChangeLog | 4 ++ configure.ac | 2 +- plugins/omudpspoof/omudpspoof.c | 97 ++++++++++++++++++++++++++++++++++------- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6114dee3..e6e8d94e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ ---------------------------------------------------------------------------- Version 7.2.5 [v7-stable] 2013-01-?? +- omudpspoof: add support for packets larger than 1472 bytes + On Ethernet, they need to be transmitted in multiple fragments. While + it is known that fragmentation can cause issues, it is the best choice + to be made in that case. Also improved debug output. - build system cleanup (thanks to Michael Biebl for this!) - bugfix: omelasticsearch did not properly compile on some platforms due to missing libmath. Thanks to Michael Biebl for the fix diff --git a/configure.ac b/configure.ac index 70e89d4d..3e3bc564 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[7.2.4],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[7.2.4.up1],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index c692acfb..c34e508e 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -316,6 +316,7 @@ CODESTARTdbgPrintInstInfo ENDdbgPrintInstInfo +#define MTU 1500 /* min max MTU we support - 1500 for ethernet TODO: config option? */ /* Send a message via UDP * Note: libnet is not thread-safe, so we need to ensure that only one * instance ever is calling libnet code. @@ -331,12 +332,22 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) libnet_ptag_t ip, ipo; libnet_ptag_t udp; sbool bNeedUnlock = 0; + /* hdrOffs = fragmentation flags + offset (in bytes) + * divided by 8 */ + unsigned msgOffs, hdrOffs; + unsigned maxPktLen, pktLen; DEFiRet; if(pData->pSockArray == NULL) { CHKiRet(doTryResume(pData)); } + if(len > 65528) { + DBGPRINTF("omudpspoof: msg with length %d truncated to 64k: '%.768s'\n", + len, msg); + len = 65528; + } + ip = ipo = udp = 0; if(pData->sourcePort++ >= pData->sourcePortEnd){ pData->sourcePort = pData->sourcePortStart; @@ -349,15 +360,30 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) bNeedUnlock = 1; for (r = pData->f_addr; r && bSendSuccess == RSFALSE ; r = r->ai_next) { tempaddr = (struct sockaddr_in *)r->ai_addr; + /* Getting max payload size (must be multiple of 8) */ + maxPktLen = (MTU - LIBNET_IPV4_H) & ~0x07; + msgOffs = 0; + /* We're doing (payload size - UDP header size) and not + * checking if it's a multiple of 8 because we know the + * header is 8 bytes long */ + if(len > (maxPktLen - LIBNET_UDP_H) ) { + hdrOffs = IP_MF; + pktLen = maxPktLen - LIBNET_UDP_H; + } else { + hdrOffs = 0; + pktLen = len; + } + DBGPRINTF("omudpspoof: stage 1: MF:%d, hdrOffs %d, pktLen %d\n", + (hdrOffs & IP_MF) >> 13, (hdrOffs & 0x1FFF) << 3, pktLen); libnet_clear_packet(libnet_handle); /* note: libnet does need ports in host order NOT in network byte order! -- rgerhards, 2009-11-12 */ udp = libnet_build_udp( ntohs(pData->sourcePort),/* source port */ ntohs(tempaddr->sin_port),/* destination port */ - LIBNET_UDP_H + len, /* packet length */ + pktLen+LIBNET_UDP_H, /* packet length */ 0, /* checksum */ (u_char*)msg, /* payload */ - len, /* payload size */ + pktLen, /* payload size */ libnet_handle, /* libnet handle */ udp); /* libnet id */ if (udp == -1) { @@ -365,10 +391,10 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) } ip = libnet_build_ipv4( - LIBNET_IPV4_H + len + LIBNET_UDP_H, /* length */ + LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, /* length */ 0, /* TOS */ 242, /* IP ID */ - 0, /* IP Frag */ + hdrOffs, /* IP Frag */ 64, /* TTL */ IPPROTO_UDP, /* protocol */ 0, /* checksum */ @@ -384,20 +410,62 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) /* Write it to the wire. */ lsent = libnet_write(libnet_handle); - if(lsent != LIBNET_IPV4_H+LIBNET_UDP_H+len) { - DBGPRINTF("omudpspoof: write error len %d, sent %d: %s\n", - LIBNET_IPV4_H+LIBNET_UDP_H+len, lsent, libnet_geterror(libnet_handle)); + if(lsent != (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen)) { + DBGPRINTF("omudpspoof: write error (total len %d): pktLen %d, sent %d: %s\n", + len, LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, lsent, libnet_geterror(libnet_handle)); if(lsent != -1) { bSendSuccess = RSTRUE; } } else { bSendSuccess = RSTRUE; } - } - /* finished looping */ - if(bSendSuccess == RSFALSE) { - DBGPRINTF("omudpspoof: error sending message, suspending\n"); - iRet = RS_RET_SUSPENDED; + msgOffs += pktLen; + + /* We need to get rid of the UDP header to build the other fragments */ + libnet_clear_packet(libnet_handle); + ip = LIBNET_PTAG_INITIALIZER; + while(len > msgOffs ) { /* loop until all payload is sent */ + /* check if there will be more fragments */ + if((len - msgOffs) > maxPktLen) { + /* In IP's eyes, the UDP header in the first packet + * needs to be in the offset, so we add its size to + * the payload offset here */ + hdrOffs = IP_MF + (msgOffs + LIBNET_UDP_H)/8; + pktLen = maxPktLen; + } else { + /* See above */ + hdrOffs = (msgOffs + LIBNET_UDP_H)/8; + pktLen = len - msgOffs; + } + DBGPRINTF("omudpspoof: stage 2: MF:%d, hdrOffs %d, pktLen %d\n", + (hdrOffs & IP_MF) >> 13, (hdrOffs & 0x1FFF) << 3, pktLen); + ip = libnet_build_ipv4( + LIBNET_IPV4_H + pktLen, /* length */ + 0, /* TOS */ + 242, /* IP ID */ + hdrOffs, /* IP Frag */ + 64, /* TTL */ + IPPROTO_UDP, /* protocol */ + 0, /* checksum */ + source_ip.sin_addr.s_addr, + tempaddr->sin_addr.s_addr, + (u_int8_t*)(msg+msgOffs), /* payload */ + pktLen, /* payload size */ + libnet_handle, /* libnet handle */ + ip); /* libnet id */ + if (ip == -1) { + DBGPRINTF("omudpspoof: can't build IP fragment header: %s\n", libnet_geterror(libnet_handle)); + } + /* Write it to the wire. */ + lsent = libnet_write(libnet_handle); + if(lsent != (int) (LIBNET_IPV4_H+pktLen)) { + DBGPRINTF("omudpspoof: fragment write error len %d, sent %d: %s\n", + LIBNET_IPV4_H+LIBNET_UDP_H+len, lsent, libnet_geterror(libnet_handle)); + bSendSuccess = RSFALSE; + continue; + } + msgOffs += pktLen; + } } finalize_it: @@ -422,7 +490,7 @@ static rsRetVal doTryResume(instanceData *pData) FINALIZE; /* The remote address is not yet known and needs to be obtained */ - DBGPRINTF(" %s\n", pData->host); + DBGPRINTF("omudpspoof trying resume for '%s'\n", pData->host); memset(&hints, 0, sizeof(hints)); /* port must be numeric, because config file syntax requires this */ hints.ai_flags = AI_NUMERICSERV; @@ -464,8 +532,7 @@ CODESTARTdoAction iMaxLine = glbl.GetMaxLine(); - //TODO: enable THIS one! DBGPRINTF(" %s:%s/omudpspoof, src '%s', msg strt '%.256s'\n", pData->host, - DBGPRINTF(" %s:%s/omudpspoof, src '%s', msg strt '%s'\n", pData->host, + DBGPRINTF(" %s:%s/omudpspoof, src '%s', msg strt '%.256s'\n", pData->host, getFwdPt(pData), ppString[1], ppString[0]); psz = (char*) ppString[0]; -- cgit v1.2.3 From 5eb09df8fea738f374e35fb6998cd54222a17590 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Dec 2012 14:46:31 +0100 Subject: doc: mention omudpspoof message size limits --- doc/omudpspoof.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/omudpspoof.html b/doc/omudpspoof.html index df14bbe1..a8783c9a 100644 --- a/doc/omudpspoof.html +++ b/doc/omudpspoof.html @@ -45,6 +45,11 @@ equal to the start value. Default is 42000.

Sample:

The following sample forwards all syslog messages in standard form to the -- cgit v1.2.3 From 4a7f216ac0d0447d6e27035d7e8e2201be9e641d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Dec 2012 16:17:46 +0100 Subject: omudpspoof: add support for new config system --- ChangeLog | 1 + plugins/omudpspoof/omudpspoof.c | 99 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index e6e8d94e..b439c76a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ ---------------------------------------------------------------------------- Version 7.2.5 [v7-stable] 2013-01-?? +- omudpspoof: add support for new config system - omudpspoof: add support for packets larger than 1472 bytes On Ethernet, they need to be transmitted in multiple fragments. While it is known that fragmentation can cause issues, it is the best choice diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index c34e508e..33f644e4 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -5,7 +5,7 @@ * This file builds on UDP spoofing code contributed by * David Lang . I then created a "real" rsyslog module * out of that code and omfwd. I decided to make it a separate module because - * omfwd already mixes up too many things (TCP & UDP & a differnt modes, + * omfwd already mixes up too many things (TCP & UDP & a different modes, * this has historic reasons), it would not be a good idea to also add * spoofing to it. And, looking at the requirements, there is little in * common between omfwd and this module. @@ -93,8 +93,11 @@ DEFobjCurrIf(glbl) DEFobjCurrIf(net) typedef struct _instanceData { + uchar *tplName; /* name of assigned template */ uchar *host; uchar *port; + uchar *sourceTpl; + int mtu; int *pSockArray; /* sockets to use for UDP */ int compressionLevel; /* 0 - no compression, else level for zlib */ struct addrinfo *f_addr; @@ -116,6 +119,22 @@ typedef struct configSettings_s { } configSettings_t; static configSettings_t cs; +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "target", eCmdHdlrGetWord, 1 }, + { "port", eCmdHdlrGetWord, 0 }, + { "sourcetemplate", eCmdHdlrGetWord, 0 }, + { "sourceport.start", eCmdHdlrInt, 0 }, + { "sourceport.end", eCmdHdlrInt, 0 }, + { "mtu", eCmdHdlrInt, 0 }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + /* module-global parameters */ static struct cnfparamdescr modpdescr[] = { { "template", eCmdHdlrGetWord, 0 }, @@ -305,8 +324,10 @@ BEGINfreeInstance CODESTARTfreeInstance /* final cleanup */ closeUDPSockets(pData); + free(pData->tplName); free(pData->port); free(pData->host); + free(pData->sourceTpl); ENDfreeInstance @@ -489,6 +510,9 @@ static rsRetVal doTryResume(instanceData *pData) if(pData->pSockArray != NULL) FINALIZE; + if(pData->host == NULL) + ABORT_FINALIZE(RS_RET_DISABLE_ACTION); + /* The remote address is not yet known and needs to be obtained */ DBGPRINTF("omudpspoof trying resume for '%s'\n", pData->host); memset(&hints, 0, sizeof(hints)); @@ -511,7 +535,8 @@ finalize_it: freeaddrinfo(pData->f_addr); pData->f_addr = NULL; } - iRet = RS_RET_SUSPENDED; + if(iRet != RS_RET_DISABLE_ACTION) + iRet = RS_RET_SUSPENDED; } RETiRet; @@ -587,6 +612,75 @@ finalize_it: ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->tplName = NULL; + pData->sourcePortStart = DFLT_SOURCE_PORT_START; + pData->sourcePortEnd = DFLT_SOURCE_PORT_END; + pData->host = NULL; + pData->port = NULL; + pData->sourceTpl = (uchar*) strdup("RSYSLOG_omudpspoofDfltSourceTpl"); + pData->mtu = 1500; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + uchar *tplToUse; + int i; +CODESTARTnewActInst + DBGPRINTF("newActInst (omudpspoof)\n"); + + pvals = nvlstGetParams(lst, &actpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omudpspoof: mandatory " + "parameters missing"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("action param blk in omudpspoof:\n"); + cnfparamsPrint(&actpblk, pvals); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "target")) { + pData->host = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "port")) { + pData->port = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "sourcetemplate")) { + free(pData->sourceTpl); + pData->sourceTpl = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "sourceport.start")) { + pData->sourcePortStart = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "sourceport.end")) { + pData->sourcePortEnd = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "mtu")) { + pData->mtu = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + DBGPRINTF("omudpspoof: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + CODE_STD_STRING_REQUESTnewActInst(2) + pData->sourcePort = pData->sourcePortStart; + + tplToUse = ustrdup((pData->tplName == NULL) ? getDfltTpl() : pData->tplName); + CHKiRet(OMSRsetEntry(*ppOMSR, 0, tplToUse, OMSR_NO_RQD_TPL_OPTS)); + CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->sourceTpl), OMSR_NO_RQD_TPL_OPTS)); + +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + BEGINparseSelectorAct uchar *sourceTpl; CODESTARTparseSelectorAct @@ -657,6 +751,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 6b0e4a44229d12d0ccf7b08eceeeb361d781f241 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Dec 2012 18:36:19 +0100 Subject: doc: document v7 omudpspoof config parameters --- doc/omudpspoof.html | 86 +++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 26 deletions(-) diff --git a/doc/omudpspoof.html b/doc/omudpspoof.html index a8783c9a..811c73e2 100644 --- a/doc/omudpspoof.html +++ b/doc/omudpspoof.html @@ -14,32 +14,66 @@

This module is similar to the regular UDP forwarder, but permits to spoof the sender address. Also, it enables to circle through a number of source ports. -

Configuration Directives:

+

load() Parameters:

+

 

+

action() parameters:

+ +

pre-v7 Configuration Directives:

+ Caveats/Known Bugs: -

Sample:

+

Legacy Sample (pre-v7):

The following sample forwards all syslog messages in standard form to the remote server server.example.com. The original sender's address is used. We do not care about the source port. This example is considered the typical use case for -- cgit v1.2.3 From 2ef0e994de76650e2e9da79e4fcd955d2af24930 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 09:07:39 +0100 Subject: add some better debug information to impstats --- plugins/impstats/impstats.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 62599969..1ba4548f 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -139,6 +139,8 @@ doSubmitMsg(uchar *line) pMsg->msgFlags = 0; submitMsg(pMsg); + DBGPRINTF("impstats: submit [%d,%d] msg '%s'\n", runModConf->iFacility, + runModConf->iSeverity, line); finalize_it: RETiRet; -- cgit v1.2.3 From 405313c39dbf75636787ba75659235fc9f179a4f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 09:08:32 +0100 Subject: omudpspoof: initialize libnet for each message This is a brute-force troubleshooting aid. Will later be changed to better code. --- configure.ac | 2 +- plugins/omudpspoof/omudpspoof.c | 58 ++++++++++++++++++++++------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/configure.ac b/configure.ac index 3e3bc564..f7a01414 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[7.2.4.up1],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[7.2.4.up2],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index 33f644e4..c041eec5 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -104,6 +104,8 @@ typedef struct _instanceData { u_short sourcePort; u_short sourcePortStart; /* for sorce port iteration */ u_short sourcePortEnd; + libnet_t *libnet_handle; + char errbuf[LIBNET_ERRBUF_SIZE]; } instanceData; #define DFLT_SOURCE_PORT_START 32000 @@ -167,8 +169,6 @@ ENDinitConfVars /* add some variables needed for libnet */ -libnet_t *libnet_handle; -char errbuf[LIBNET_ERRBUF_SIZE]; pthread_mutex_t mutLibnet; /* forward definitions */ @@ -310,6 +310,7 @@ ENDfreeCnf BEGINcreateInstance CODESTARTcreateInstance +finalize_it: ENDcreateInstance @@ -379,6 +380,18 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) bSendSuccess = RSFALSE; d_pthread_mutex_lock(&mutLibnet); bNeedUnlock = 1; +/* Initialize the libnet library. Root priviledges are required. +* this initializes a IPv4 socket to use for forging UDP packets. +*/ +pData->libnet_handle = libnet_init( + LIBNET_RAW4, /* injection type */ + NULL, /* network interface */ + pData->errbuf); /* errbuf */ + +if(pData->libnet_handle == NULL) { + errmsg.LogError(0, NO_ERRCODE, "Error initializing libnet, can not continue "); + ABORT_FINALIZE(RS_RET_ERR_LIBNET_INIT); +} for (r = pData->f_addr; r && bSendSuccess == RSFALSE ; r = r->ai_next) { tempaddr = (struct sockaddr_in *)r->ai_addr; /* Getting max payload size (must be multiple of 8) */ @@ -396,7 +409,7 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) } DBGPRINTF("omudpspoof: stage 1: MF:%d, hdrOffs %d, pktLen %d\n", (hdrOffs & IP_MF) >> 13, (hdrOffs & 0x1FFF) << 3, pktLen); - libnet_clear_packet(libnet_handle); + libnet_clear_packet(pData->libnet_handle); /* note: libnet does need ports in host order NOT in network byte order! -- rgerhards, 2009-11-12 */ udp = libnet_build_udp( ntohs(pData->sourcePort),/* source port */ @@ -405,10 +418,10 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) 0, /* checksum */ (u_char*)msg, /* payload */ pktLen, /* payload size */ - libnet_handle, /* libnet handle */ + pData->libnet_handle, /* libnet handle */ udp); /* libnet id */ if (udp == -1) { - DBGPRINTF("omudpspoof: can't build UDP header: %s\n", libnet_geterror(libnet_handle)); + DBGPRINTF("omudpspoof: can't build UDP header: %s\n", libnet_geterror(pData->libnet_handle)); } ip = libnet_build_ipv4( @@ -423,17 +436,19 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) tempaddr->sin_addr.s_addr, NULL, /* payload */ 0, /* payload size */ - libnet_handle, /* libnet handle */ + pData->libnet_handle, /* libnet handle */ ip); /* libnet id */ if (ip == -1) { - DBGPRINTF("omudpspoof: can't build IP header: %s\n", libnet_geterror(libnet_handle)); + DBGPRINTF("omudpspoof: can't build IP header: %s\n", libnet_geterror(pData->libnet_handle)); } /* Write it to the wire. */ - lsent = libnet_write(libnet_handle); +dbgprintf("DDDD: omudpspoof fd %d\n", pData->libnet_handle->fd); + lsent = libnet_write(pData->libnet_handle); + dbgprintf("DDDD: omudpspoof stage 1 return state %d (expected %d)\n", lsent, (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen)); if(lsent != (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen)) { DBGPRINTF("omudpspoof: write error (total len %d): pktLen %d, sent %d: %s\n", - len, LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, lsent, libnet_geterror(libnet_handle)); + len, LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, lsent, libnet_geterror(pData->libnet_handle)); if(lsent != -1) { bSendSuccess = RSTRUE; } @@ -443,7 +458,7 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) msgOffs += pktLen; /* We need to get rid of the UDP header to build the other fragments */ - libnet_clear_packet(libnet_handle); + libnet_clear_packet(pData->libnet_handle); ip = LIBNET_PTAG_INITIALIZER; while(len > msgOffs ) { /* loop until all payload is sent */ /* check if there will be more fragments */ @@ -472,16 +487,17 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) tempaddr->sin_addr.s_addr, (u_int8_t*)(msg+msgOffs), /* payload */ pktLen, /* payload size */ - libnet_handle, /* libnet handle */ + pData->libnet_handle, /* libnet handle */ ip); /* libnet id */ if (ip == -1) { - DBGPRINTF("omudpspoof: can't build IP fragment header: %s\n", libnet_geterror(libnet_handle)); + DBGPRINTF("omudpspoof: can't build IP fragment header: %s\n", libnet_geterror(pData->libnet_handle)); } /* Write it to the wire. */ - lsent = libnet_write(libnet_handle); + lsent = libnet_write(pData->libnet_handle); + dbgprintf("DDDD: omudpspoof stage 1 return state %d (expected %d)\n", lsent, (int) (LIBNET_IPV4_H+pktLen)); if(lsent != (int) (LIBNET_IPV4_H+pktLen)) { DBGPRINTF("omudpspoof: fragment write error len %d, sent %d: %s\n", - LIBNET_IPV4_H+LIBNET_UDP_H+len, lsent, libnet_geterror(libnet_handle)); + LIBNET_IPV4_H+LIBNET_UDP_H+len, lsent, libnet_geterror(pData->libnet_handle)); bSendSuccess = RSFALSE; continue; } @@ -491,6 +507,7 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) finalize_it: if(bNeedUnlock) { +libnet_destroy(pData->libnet_handle); d_pthread_mutex_unlock(&mutLibnet); } RETiRet; @@ -738,7 +755,6 @@ freeConfigVars(void) BEGINmodExit CODESTARTmodExit /* destroy the libnet state needed for forged UDP sources */ - libnet_destroy(libnet_handle); pthread_mutex_destroy(&mutLibnet); /* release what we no longer need */ objRelease(errmsg, CORE_COMPONENT); @@ -779,18 +795,6 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net,LM_NET_FILENAME)); - /* Initialize the libnet library. Root priviledges are required. - * this initializes a IPv4 socket to use for forging UDP packets. - */ - libnet_handle = libnet_init( - LIBNET_RAW4, /* injection type */ - NULL, /* network interface */ - errbuf); /* errbuf */ - - if(libnet_handle == NULL) { - errmsg.LogError(0, NO_ERRCODE, "Error initializing libnet, can not continue "); - ABORT_FINALIZE(RS_RET_ERR_LIBNET_INIT); - } pthread_mutex_init(&mutLibnet, NULL); CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofdefaulttemplate", 0, eCmdHdlrGetWord, setLegacyDfltTpl, NULL, NULL)); -- cgit v1.2.3 From 5d2dd9d7581b5e2382580151ca53c835ee02abd9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 09:18:15 +0100 Subject: omudpspoof: add action parameter for mtu size --- doc/omfwd.html | 2 +- plugins/omudpspoof/omudpspoof.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/omfwd.html b/doc/omfwd.html index 5599ae39..fb9145e1 100644 --- a/doc/omfwd.html +++ b/doc/omfwd.html @@ -16,7 +16,7 @@

Global Configuration Directives:

 

diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index c041eec5..a9c48351 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -310,7 +310,7 @@ ENDfreeCnf BEGINcreateInstance CODESTARTcreateInstance -finalize_it: + pData->mtu = 1500; ENDcreateInstance @@ -338,7 +338,6 @@ CODESTARTdbgPrintInstInfo ENDdbgPrintInstInfo -#define MTU 1500 /* min max MTU we support - 1500 for ethernet TODO: config option? */ /* Send a message via UDP * Note: libnet is not thread-safe, so we need to ensure that only one * instance ever is calling libnet code. @@ -395,7 +394,7 @@ if(pData->libnet_handle == NULL) { for (r = pData->f_addr; r && bSendSuccess == RSFALSE ; r = r->ai_next) { tempaddr = (struct sockaddr_in *)r->ai_addr; /* Getting max payload size (must be multiple of 8) */ - maxPktLen = (MTU - LIBNET_IPV4_H) & ~0x07; + maxPktLen = (pData->mtu - LIBNET_IPV4_H) & ~0x07; msgOffs = 0; /* We're doing (payload size - UDP header size) and not * checking if it's a multiple of 8 because we know the -- cgit v1.2.3 From 97d6350b9fa58e6fc8898f639c898fb9c8a553b8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 09:34:21 +0100 Subject: doc: added v7 conf samples to omudpspoof doc --- doc/omudpspoof.html | 82 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 5 deletions(-) diff --git a/doc/omudpspoof.html b/doc/omudpspoof.html index 811c73e2..ffbd04e1 100644 --- a/doc/omudpspoof.html +++ b/doc/omudpspoof.html @@ -7,9 +7,10 @@

UDP spoofing output module (omudpspoof)

Module Name:    omstdout

-

Author: David Lang <david@lang.hm> and Rainer Gerhards -<rgerhards@adiscon.com>

-

Available Since: 5.1.3

+

Authors: Rainer Gerhards <rgerhards@adiscon.com> +and David Lang <david@lang.hm> +

+

Available Since: 5.1.3 / v7 config since 7.2.5

Description:

This module is similar to the regular UDP forwarder, but permits to spoof the sender address. Also, it enables to circle through a number of @@ -33,7 +34,7 @@ source ports. Template to use as message text.

-

  • sourcetemplate [Word]
    +
  • SourceTemplate [Word]
    This is the name of the template that contains a numerical IP address that is to be used as the source system IP address. While it may often be a constant value, it can be generated as usual via the @@ -59,7 +60,7 @@ source ports. Maximum MTU supported by the network. Default respects Ethernet and must usually not be adjusted. Setting a too-high MTU can lead to message loss, too low to excess message fragmentation. Change only if you really know what - you are doing. + you are doing. This is always given in number of bytes.

  • pre-v7 Configuration Directives:

    @@ -85,6 +86,77 @@ fragmented, up to a total upper limit of 64K (induced by UDP). Message sizes ove 64K will be truncated. For older versions, messages over 1472 may be totally discarded or truncated, depending on version and environment. + +

    Config Samples

    +

    The following sample forwards all syslog messages in standard form to the +remote server server.example.com. The original sender's address is used. We do not +care about the source port. This example is considered the typical use case for +omudpspoof. +

    + + +

    The following sample forwards all syslog messages in unmodified form to the +remote server server.example.com. The sender address 192.0.2.1 with fixed +source port 514 is used. +

    + +

    The following sample is exatly like the previous, but it specifies a larger size +MTU. If, for example, the envrionment supports Jumbo Ethernet frames, increasing the +MTU is useful as it reduces packet fragmentation, which most often is the source of +problems. Note that setting the MTU to a value larger than the local-attached network +supports will lead to send errors and loss of message. So use with care! +

    + +

    Of course, the action can be combined with any type of filter, for +example a tradition PRI filter:

    + +

    ... or any complex expression-based filter:

    + +

    and of course it can also be combined with as many other actions +as one likes:

    + +

    Legacy Sample (pre-v7):

    The following sample forwards all syslog messages in standard form to the remote server server.example.com. The original sender's address is used. We do not -- cgit v1.2.3 From 03ff013c2412c27ef1c4cb580f55c912a6fbab3f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 09:56:55 +0100 Subject: omudpspoof: improve libnet calling sequence retains bugfix while increasing performance again --- ChangeLog | 5 ++++ doc/omudpspoof.html | 4 +++ plugins/omudpspoof/omudpspoof.c | 60 ++++++++++++++++++++++++++++------------- runtime/rsyslog.h | 1 + 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index b439c76a..fb8547c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,11 @@ Version 7.2.5 [v7-stable] 2013-01-?? On Ethernet, they need to be transmitted in multiple fragments. While it is known that fragmentation can cause issues, it is the best choice to be made in that case. Also improved debug output. +- bugfix: omudpspoof failed depending on the execution environment + The v7 engine closes fds, and closed some of libnet's fds as well, what + lead to problems (unfortunately, at least some libnet versions do not + report a proper error state but still "success"...). The order of libnet + calls has been adjusted to by in sync with what the core engine does. - build system cleanup (thanks to Michael Biebl for this!) - bugfix: omelasticsearch did not properly compile on some platforms due to missing libmath. Thanks to Michael Biebl for the fix diff --git a/doc/omudpspoof.html b/doc/omudpspoof.html index ffbd04e1..930412c8 100644 --- a/doc/omudpspoof.html +++ b/doc/omudpspoof.html @@ -15,6 +15,10 @@ and David Lang <david@lang.hm>

    This module is similar to the regular UDP forwarder, but permits to spoof the sender address. Also, it enables to circle through a number of source ports. +

    Important: This module requires root priveleges for its low-level +socket access. As such, the module will not work if rsyslog is configured to +drop privileges. +

    load() Parameters:

    • Template [templateName]
      diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index a9c48351..c0ed7e7e 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -104,6 +104,7 @@ typedef struct _instanceData { u_short sourcePort; u_short sourcePortStart; /* for sorce port iteration */ u_short sourcePortEnd; + int bReportLibnetInitErr; /* help prevent multiple error messages on init err */ libnet_t *libnet_handle; char errbuf[LIBNET_ERRBUF_SIZE]; } instanceData; @@ -310,7 +311,9 @@ ENDfreeCnf BEGINcreateInstance CODESTARTcreateInstance + pData->libnet_handle = NULL; pData->mtu = 1500; + pData->bReportLibnetInitErr = 1; ENDcreateInstance @@ -329,6 +332,8 @@ CODESTARTfreeInstance free(pData->port); free(pData->host); free(pData->sourceTpl); + if(pData->libnet_handle != NULL) + libnet_destroy(pData->libnet_handle); ENDfreeInstance @@ -379,18 +384,6 @@ UDPSend(instanceData *pData, uchar *pszSourcename, char *msg, size_t len) bSendSuccess = RSFALSE; d_pthread_mutex_lock(&mutLibnet); bNeedUnlock = 1; -/* Initialize the libnet library. Root priviledges are required. -* this initializes a IPv4 socket to use for forging UDP packets. -*/ -pData->libnet_handle = libnet_init( - LIBNET_RAW4, /* injection type */ - NULL, /* network interface */ - pData->errbuf); /* errbuf */ - -if(pData->libnet_handle == NULL) { - errmsg.LogError(0, NO_ERRCODE, "Error initializing libnet, can not continue "); - ABORT_FINALIZE(RS_RET_ERR_LIBNET_INIT); -} for (r = pData->f_addr; r && bSendSuccess == RSFALSE ; r = r->ai_next) { tempaddr = (struct sockaddr_in *)r->ai_addr; /* Getting max payload size (must be multiple of 8) */ @@ -442,12 +435,17 @@ if(pData->libnet_handle == NULL) { } /* Write it to the wire. */ -dbgprintf("DDDD: omudpspoof fd %d\n", pData->libnet_handle->fd); lsent = libnet_write(pData->libnet_handle); - dbgprintf("DDDD: omudpspoof stage 1 return state %d (expected %d)\n", lsent, (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen)); + dbgprintf("DDDD: omudpspoof stage 1 return state %d (expected %d), fd %d\n", lsent, + (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen), pData->libnet_handle->fd); if(lsent != (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen)) { - DBGPRINTF("omudpspoof: write error (total len %d): pktLen %d, sent %d: %s\n", - len, LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, lsent, libnet_geterror(pData->libnet_handle)); + /* note: access to fd is a libnet internal. If a newer version of libnet does + * not expose that member, we should simply remove it. However, while it is there + * it is useful for consolidating with strace output. + */ + DBGPRINTF("omudpspoof: write error (total len %d): pktLen %d, sent %d, fd %d: %s\n", + len, LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, lsent, pData->libnet_handle->fd, + libnet_geterror(pData->libnet_handle)); if(lsent != -1) { bSendSuccess = RSTRUE; } @@ -485,7 +483,7 @@ dbgprintf("DDDD: omudpspoof fd %d\n", pData->libnet_handle->fd); source_ip.sin_addr.s_addr, tempaddr->sin_addr.s_addr, (u_int8_t*)(msg+msgOffs), /* payload */ - pktLen, /* payload size */ + pktLen, /* payload size */ pData->libnet_handle, /* libnet handle */ ip); /* libnet id */ if (ip == -1) { @@ -505,8 +503,13 @@ dbgprintf("DDDD: omudpspoof fd %d\n", pData->libnet_handle->fd); } finalize_it: + if(iRet != RS_RET_OK) { + if(pData->libnet_handle != NULL) { + libnet_destroy(pData->libnet_handle); + pData->libnet_handle = NULL; + } + } if(bNeedUnlock) { -libnet_destroy(pData->libnet_handle); d_pthread_mutex_unlock(&mutLibnet); } RETiRet; @@ -529,6 +532,27 @@ static rsRetVal doTryResume(instanceData *pData) if(pData->host == NULL) ABORT_FINALIZE(RS_RET_DISABLE_ACTION); + if(pData->libnet_handle == NULL) { + /* Initialize the libnet library. Root priviledges are required. + * this initializes a IPv4 socket to use for forging UDP packets. + */ + pData->libnet_handle = libnet_init( + LIBNET_RAW4, /* injection type */ + NULL, /* network interface */ + pData->errbuf); /* errbuf */ + + if(pData->libnet_handle == NULL) { + if(pData->bReportLibnetInitErr) { + errmsg.LogError(0, RS_RET_LIBNET_INIT_FAILED, "omudpsoof: error " + "initializing libnet - are you running as root?"); + pData->bReportLibnetInitErr = 0; + } + ABORT_FINALIZE(RS_RET_ERR_LIBNET_INIT); + } + } + DBGPRINTF("omudpspoof: libnit_init() ok\n"); + pData->bReportLibnetInitErr = 1; + /* The remote address is not yet known and needs to be obtained */ DBGPRINTF("omudpspoof trying resume for '%s'\n", pData->host); memset(&hints, 0, sizeof(hints)); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 07d58d68..d85109c3 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -393,6 +393,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_INVLD_SETOP = -2305, /**< invalid variable set operation, incompatible type */ RS_RET_RULESET_EXISTS = -2306,/**< ruleset already exists */ RS_RET_DEPRECATED = -2307,/**< deprecated functionality is used */ + RS_RET_LIBNET_INIT_FAILED = -2308,/**< libnet_init() failed, probably because of not running as root */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit v1.2.3 From 6f8b8ebd9b806cdd7f799e8d3c737eddefdda31e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 10:01:26 +0100 Subject: omudpspoof: remove dead code On-the-fly compression support code was present since the initial module was written, however, no config options existed to actually activate it. I have now removed that code for clarity (obviously there is no need to maintain it or add the feature - nobody ever complained in the past...) --- plugins/omudpspoof/omudpspoof.c | 47 ++--------------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index c0ed7e7e..82331e17 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -99,7 +99,6 @@ typedef struct _instanceData { uchar *sourceTpl; int mtu; int *pSockArray; /* sockets to use for UDP */ - int compressionLevel; /* 0 - no compression, else level for zlib */ struct addrinfo *f_addr; u_short sourcePort; u_short sourcePortStart; /* for sorce port iteration */ @@ -590,62 +589,20 @@ ENDtryResume BEGINdoAction char *psz; /* temporary buffering */ - register unsigned l; + unsigned l; int iMaxLine; CODESTARTdoAction CHKiRet(doTryResume(pData)); - iMaxLine = glbl.GetMaxLine(); - DBGPRINTF(" %s:%s/omudpspoof, src '%s', msg strt '%.256s'\n", pData->host, getFwdPt(pData), ppString[1], ppString[0]); + iMaxLine = glbl.GetMaxLine(); psz = (char*) ppString[0]; l = strlen((char*) psz); if((int) l > iMaxLine) l = iMaxLine; -# ifdef USE_NETZIP - /* Check if we should compress and, if so, do it. We also - * check if the message is large enough to justify compression. - * The smaller the message, the less likely is a gain in compression. - * To save CPU cycles, we do not try to compress very small messages. - * What "very small" means needs to be configured. Currently, it is - * hard-coded but this may be changed to a config parameter. - * rgerhards, 2006-11-30 - */ - if(pData->compressionLevel && (l > CONF_MIN_SIZE_FOR_COMPRESS)) { - Bytef *out; - uLongf destLen = iMaxLine + iMaxLine/100 +12; /* recommended value from zlib doc */ - uLong srcLen = l; - int ret; - /* TODO: optimize malloc sequence? -- rgerhards, 2008-09-02 */ - CHKmalloc(out = (Bytef*) MALLOC(destLen)); - out[0] = 'z'; - out[1] = '\0'; - ret = compress2((Bytef*) out+1, &destLen, (Bytef*) psz, - srcLen, pData->compressionLevel); - DBGPRINTF("Compressing message, length was %d now %d, return state %d.\n", - l, (int) destLen, ret); - if(ret != Z_OK) { - /* if we fail, we complain, but only in debug mode - * Otherwise, we are silent. In any case, we ignore the - * failed compression and just sent the uncompressed - * data, which is still valid. So this is probably the - * best course of action. - * rgerhards, 2006-11-30 - */ - DBGPRINTF("Compression failed, sending uncompressed message\n"); - } else if(destLen+1 < l) { - /* only use compression if there is a gain in using it! */ - DBGPRINTF("there is gain in compression, so we do it\n"); - psz = (char*) out; - l = destLen + 1; /* take care for the "z" at message start! */ - } - ++destLen; - } -# endif - CHKiRet(UDPSend(pData, ppString[1], psz, l)); finalize_it: -- cgit v1.2.3 From fbffd924e67cdd531dfdc2ccdddba59bd0b33752 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 18 Dec 2012 11:47:37 +0100 Subject: version number increase for experimental version --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f7a01414..193f2df7 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[7.2.4.up2],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[7.2.4.up3],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3