1 /* omudpspoof.c
2  *
3  * This is a udp-based output module that support spoofing.
4  *
5  * This file builds on UDP spoofing code contributed by
6  * David Lang <david@lang.hm>. I then created a "real" rsyslog module
7  * out of that code and omfwd. I decided to make it a separate module because
8  * omfwd already mixes up too many things (TCP & UDP & a different modes,
9  * this has historic reasons), it would not be a good idea to also add
10  * spoofing to it. And, looking at the requirements, there is little in
11  * common between omfwd and this module.
12  *
13  * Note: I have briefly checked libnet source code and I somewhat have the feeling
14  * that under some circumstances we may get into trouble with the lib. For
15  * example, it registers an atexit() handler, which should not play nicely
16  * with our dynamically loaded modules. Anyhow, I refrain from looking deeper
17  * at libnet code, especially as testing does not show any real issues. If some
18  * occur, it may be easier to modify libnet for dynamic load environments than
19  * using a work-around (as a side not, libnet looks somewhat unmaintained, the CVS
20  * I can see on sourceforge dates has no updates done less than 7 years ago).
21  * On the other hand, it looks like libnet is thread safe (at least is appropriately
22  * compiled, which I hope the standard packages are). So I do not guard calls to
23  * it with my own mutex calls.
24  * rgerhards, 2009-07-10
25  *
26  * Copyright 2009 David Lang (spoofing code)
27  * Copyright 2009-2016 Rainer Gerhards and Adiscon GmbH.
28  *
29  * This file is part of rsyslog.
30  *
31  * Rsyslog is free software: you can redistribute it and/or modify
32  * it under the terms of the GNU General Public License as published by
33  * the Free Software Foundation, either version 3 of the License, or
34  * (at your option) any later version.
35  *
36  * Rsyslog is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39  * GNU General Public License for more details.
40  *
41  * You should have received a copy of the GNU General Public License
42  * along with Rsyslog.  If not, see <http://www.gnu.org/licenses/>.
43  *
44  * A copy of the GPL can be found in the file "COPYING" in this distribution.
45  */
46 #include "config.h"
47 #include "rsyslog.h"
48 #include <stdio.h>
49 #include <stdarg.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <time.h>
53 #include <netinet/in.h>
54 #include <netdb.h>
55 #include <fnmatch.h>
56 #include <assert.h>
57 #include <errno.h>
58 #include <ctype.h>
59 #include <unistd.h>
60 #include "conf.h"
61 #include "syslogd-types.h"
62 #include "srUtils.h"
63 #include "net.h"
64 #include "template.h"
65 #include "msg.h"
66 #include "cfsysline.h"
67 #include "module-template.h"
68 #include "glbl.h"
69 #include "errmsg.h"
70 #include "dirty.h"
71 #include "unicode-helper.h"
72 #include "debug.h"
73 
74 
75 #include <libnet.h>
76 #define _BSD_SOURCE 1
77 #define __BSD_SOURCE 1
78 #define __FAVOR_BSD 1
79 
80 
81 MODULE_TYPE_OUTPUT
82 MODULE_TYPE_NOKEEP
83 MODULE_CNFNAME("omudpspoof")
84 
85 /* internal structures
86  */
87 DEF_OMOD_STATIC_DATA
88 DEFobjCurrIf(glbl)
89 DEFobjCurrIf(net)
90 
91 typedef struct _instanceData {
92 	uchar 	*tplName;	/* name of assigned template */
93 	uchar	*host;
94 	uchar	*port;
95 	uchar	*sourceTpl;
96 	int	mtu;
97 	u_short sourcePortStart;	/* for sorce port iteration */
98 	u_short sourcePortEnd;
99 	int	bReportLibnetInitErr; /* help prevent multiple error messages on init err */
100 } instanceData;
101 
102 typedef struct wrkrInstanceData {
103 	instanceData *pData;
104 	libnet_t *libnet_handle;
105 	u_short sourcePort;
106 	int	*pSockArray;		/* sockets to use for UDP */
107 	struct addrinfo *f_addr;
108 	char errbuf[LIBNET_ERRBUF_SIZE];
109 } wrkrInstanceData_t;
110 
111 #define DFLT_SOURCE_PORT_START 32000
112 #define DFLT_SOURCE_PORT_END   42000
113 
114 typedef struct configSettings_s {
115 	uchar *tplName; /* name of the default template to use */
116 	uchar *pszSourceNameTemplate; /* name of the template containing the spoofing address */
117 	uchar *pszTargetHost;
118 	uchar *pszTargetPort;
119 	int iSourcePortStart;
120 	int iSourcePortEnd;
121 } configSettings_t;
122 static configSettings_t cs;
123 
124 /* action (instance) parameters */
125 static struct cnfparamdescr actpdescr[] = {
126 	{ "target", eCmdHdlrGetWord, 1 },
127 	{ "port", eCmdHdlrGetWord, 0 },
128 	{ "sourcetemplate", eCmdHdlrGetWord, 0 },
129 	{ "sourceport.start", eCmdHdlrInt, 0 },
130 	{ "sourceport.end", eCmdHdlrInt, 0 },
131 	{ "mtu", eCmdHdlrInt, 0 },
132 	{ "template", eCmdHdlrGetWord, 0 }
133 };
134 static struct cnfparamblk actpblk =
135 	{ CNFPARAMBLK_VERSION,
136 	  sizeof(actpdescr)/sizeof(struct cnfparamdescr),
137 	  actpdescr
138 	};
139 
140 /* module-global parameters */
141 static struct cnfparamdescr modpdescr[] = {
142 	{ "template", eCmdHdlrGetWord, 0 },
143 };
144 static struct cnfparamblk modpblk =
145 	{ CNFPARAMBLK_VERSION,
146 	  sizeof(modpdescr)/sizeof(struct cnfparamdescr),
147 	  modpdescr
148 	};
149 
150 struct modConfData_s {
151 	rsconf_t *pConf;	/* our overall config object */
152 	uchar 	*tplName;	/* default template */
153 };
154 
155 static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
156 static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */
157 
158 BEGINinitConfVars		/* (re)set config variables to default values */
159 CODESTARTinitConfVars
160 	cs.tplName = NULL;
161 	cs.pszSourceNameTemplate = NULL;
162 	cs.pszTargetHost = NULL;
163 	cs.pszTargetPort = NULL;
164 	cs.iSourcePortStart = DFLT_SOURCE_PORT_START;
165 	cs.iSourcePortEnd = DFLT_SOURCE_PORT_END;
166 ENDinitConfVars
167 
168 
169 /* add some variables needed for libnet */
170 pthread_mutex_t mutLibnet;
171 
172 /* forward definitions */
173 static rsRetVal doTryResume(wrkrInstanceData_t *pWrkrData);
174 
175 /* this function gets the default template. It coordinates action between
176  * old-style and new-style configuration parts.
177  */
178 static uchar*
getDfltTpl(void)179 getDfltTpl(void)
180 {
181 	if(loadModConf != NULL && loadModConf->tplName != NULL)
182 		return loadModConf->tplName;
183 	else if(cs.tplName == NULL)
184 		return (uchar*)"RSYSLOG_TraditionalForwardFormat";
185 	else
186 		return cs.tplName;
187 }
188 
189 
190 /* set the default template to be used
191  * This is a module-global parameter, and as such needs special handling. It needs to
192  * be coordinated with values set via the v2 config system (rsyslog v6+). What we do
193  * is we do not permit this directive after the v2 config system has been used to set
194  * the parameter.
195  */
196 static rsRetVal
setLegacyDfltTpl(void * pVal,uchar * newVal)197 setLegacyDfltTpl(void __attribute__((unused)) *pVal, uchar* newVal)
198 {
199 	DEFiRet;
200 
201 	if(loadModConf != NULL && loadModConf->tplName != NULL) {
202 		free(newVal);
203 		LogError(0, RS_RET_ERR, "omudpspoof default template already set via module "
204 			"global parameter - can no longer be changed");
205 		ABORT_FINALIZE(RS_RET_ERR);
206 	}
207 	free(cs.tplName);
208 	cs.tplName = newVal;
209 finalize_it:
210 	RETiRet;
211 }
212 
213 /* Close the UDP sockets.
214  * rgerhards, 2009-05-29
215  */
216 static rsRetVal
closeUDPSockets(wrkrInstanceData_t * pWrkrData)217 closeUDPSockets(wrkrInstanceData_t *pWrkrData)
218 {
219 	DEFiRet;
220 	if(pWrkrData->pSockArray != NULL) {
221 		net.closeUDPListenSockets(pWrkrData->pSockArray);
222 		pWrkrData->pSockArray = NULL;
223 		freeaddrinfo(pWrkrData->f_addr);
224 		pWrkrData->f_addr = NULL;
225 	}
226 	RETiRet;
227 }
228 
229 
230 /* get the syslog forward port
231  * We may change the implementation to try to lookup the port
232  * if it is unspecified. So far, we use the IANA default auf 514.
233  * rgerhards, 2007-06-28
234  */
getFwdPt(instanceData * pData)235 static inline uchar *getFwdPt(instanceData *pData)
236 {
237 	return (pData->port == NULL) ? UCHAR_CONSTANT("514") : pData->port;
238 }
239 
240 
241 BEGINbeginCnfLoad
242 CODESTARTbeginCnfLoad
243 	loadModConf = pModConf;
244 	pModConf->pConf = pConf;
245 	pModConf->tplName = NULL;
246 ENDbeginCnfLoad
247 
248 BEGINsetModCnf
249 	struct cnfparamvals *pvals = NULL;
250 	int i;
251 CODESTARTsetModCnf
252 	pvals = nvlstGetParams(lst, &modpblk, NULL);
253 	if(pvals == NULL) {
254 		LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module "
255 				"config parameters [module(...)]");
256 		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
257 	}
258 
259 	if(Debug) {
260 		dbgprintf("module (global) param blk for omudpspoof:\n");
261 		cnfparamsPrint(&modpblk, pvals);
262 	}
263 
264 	for(i = 0 ; i < modpblk.nParams ; ++i) {
265 		if(!pvals[i].bUsed)
266 			continue;
267 		if(!strcmp(modpblk.descr[i].name, "template")) {
268 			loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
269 			if(cs.tplName != NULL) {
270 				LogError(0, RS_RET_DUP_PARAM, "omudpspoof: warning: default template "
271 						"was already set via legacy directive - may lead to inconsistent "
272 						"results.");
273 			}
274 		} else {
275 			dbgprintf("omudpspoof: program error, non-handled "
276 			  "param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
277 		}
278 	}
279 finalize_it:
280 	if(pvals != NULL)
281 		cnfparamvalsDestruct(pvals, &modpblk);
282 ENDsetModCnf
283 
284 BEGINendCnfLoad
285 CODESTARTendCnfLoad
286 	loadModConf = NULL; /* done loading */
287 	/* free legacy config vars */
288 	free(cs.tplName);
289 	cs.tplName = NULL;
290 ENDendCnfLoad
291 
292 BEGINcheckCnf
293 CODESTARTcheckCnf
294 ENDcheckCnf
295 
296 BEGINactivateCnf
297 CODESTARTactivateCnf
298 	runModConf = pModConf;
299 ENDactivateCnf
300 
301 BEGINfreeCnf
302 CODESTARTfreeCnf
303 	free(pModConf->tplName);
304 ENDfreeCnf
305 
306 
307 BEGINcreateInstance
308 CODESTARTcreateInstance
309 	pData->mtu = 1500;
310 	pData->bReportLibnetInitErr = 1;
311 ENDcreateInstance
312 
313 
314 BEGINcreateWrkrInstance
315 CODESTARTcreateWrkrInstance
316 	pWrkrData->libnet_handle = NULL;
317 	pWrkrData->sourcePort = pData->sourcePortStart;
318 ENDcreateWrkrInstance
319 
320 BEGINisCompatibleWithFeature
321 CODESTARTisCompatibleWithFeature
322 	if(eFeat == sFEATURERepeatedMsgReduction)
323 		iRet = RS_RET_OK;
324 ENDisCompatibleWithFeature
325 
326 
327 BEGINfreeInstance
328 CODESTARTfreeInstance
329 	/* final cleanup */
330 	free(pData->tplName);
331 	free(pData->port);
332 	free(pData->host);
333 	free(pData->sourceTpl);
334 ENDfreeInstance
335 
336 BEGINfreeWrkrInstance
337 CODESTARTfreeWrkrInstance
338 	closeUDPSockets(pWrkrData);
339 	if(pWrkrData->libnet_handle != NULL)
340 		libnet_destroy(pWrkrData->libnet_handle);
341 ENDfreeWrkrInstance
342 
343 
344 BEGINdbgPrintInstInfo
345 CODESTARTdbgPrintInstInfo
346 	DBGPRINTF("%s", pData->host);
347 ENDdbgPrintInstInfo
348 
349 
350 /* Send a message via UDP
351  * Note: libnet is not thread-safe, so we need to ensure that only one
352  * instance ever is calling libnet code.
353  * rgehards, 2007-12-20
354  */
355 #ifdef __GNUC__
356 #pragma GCC diagnostic push
357 #pragma GCC diagnostic ignored "-Wcast-align"
358 #endif
359 static rsRetVal
UDPSend(wrkrInstanceData_t * pWrkrData,uchar * pszSourcename,char * msg,size_t len)360 UDPSend(wrkrInstanceData_t *pWrkrData, uchar *pszSourcename, char *msg, size_t len)
361 {
362 	struct addrinfo *r;
363 	int lsent = 0;
364 	int bSendSuccess;
365 	instanceData *pData;
366 	struct sockaddr_in *tempaddr,source_ip;
367 	libnet_ptag_t ip;
368 	libnet_ptag_t udp;
369 	sbool bNeedUnlock = 0;
370 	/* hdrOffs = fragmentation flags + offset (in bytes)
371 	* divided by 8 */
372 	unsigned msgOffs, hdrOffs;
373 	unsigned maxPktLen, pktLen, udpPktLen;
374 	uint16_t ip_id;
375 	DEFiRet;
376 
377 	if(pWrkrData->pSockArray == NULL) {
378 		CHKiRet(doTryResume(pWrkrData));
379 	}
380 	pData = pWrkrData->pData;
381 
382 	if(len > 65528) {
383 		DBGPRINTF("omudpspoof: msg with length %d truncated to 64k: '%.768s'\n",
384 			  (int) len, msg);
385 		len = 65528;
386 	}
387 
388 	ip = udp = 0;
389 	if(pWrkrData->sourcePort++ >= pData->sourcePortEnd){
390 		pWrkrData->sourcePort = pData->sourcePortStart;
391 	}
392 
393 	/* We need a non-zero id number for the IP headers,
394 	* otherwise libnet will increase it after each
395 	* build_ipv4, breaking the fragments */
396 	ip_id = (uint16_t)libnet_get_prand(LIBNET_PR16);
397 
398 	inet_pton(AF_INET, (char*)pszSourcename, &(source_ip.sin_addr));
399 	bSendSuccess = RSFALSE;
400 	d_pthread_mutex_lock(&mutLibnet);
401 	bNeedUnlock = 1;
402 	for (r = pWrkrData->f_addr; r && bSendSuccess == RSFALSE ; r = r->ai_next) {
403 		tempaddr = (struct sockaddr_in *)r->ai_addr;
404 		/* Getting max payload size (must be multiple of 8) */
405 		maxPktLen = (pData->mtu - LIBNET_IPV4_H) & ~0x07;
406 		msgOffs = 0;
407 		/* We're doing (payload size - UDP header size) and not
408 		* checking if it's a multiple of 8 because we know the
409 		* header is 8 bytes long */
410 		if(len > (maxPktLen - LIBNET_UDP_H) ) {
411 			hdrOffs = IP_MF;
412 			pktLen = maxPktLen - LIBNET_UDP_H;
413 			udpPktLen = len;
414 		} else {
415 			hdrOffs = 0;
416 			pktLen = len;
417 			udpPktLen = len;
418 		}
419 		DBGPRINTF("omudpspoof: stage 1: MF:%d, msgOffs %d, hdrOffs %d, pktLen %d, udpPktLen %d, maxPktLen %d\n",
420 			  (hdrOffs & IP_MF) >> 13, (hdrOffs & 0x1FFF) << 3, hdrOffs, pktLen, udpPktLen, maxPktLen);
421 		libnet_clear_packet(pWrkrData->libnet_handle);
422 
423 		/* note: libnet does need ports in host order NOT in network byte order! -- rgerhards, 2009-11-12 */
424 		udp = libnet_build_udp(
425 			pWrkrData->sourcePort,		/* source port */
426 			ntohs(tempaddr->sin_port),	/* destination port */
427 			udpPktLen+LIBNET_UDP_H,		/* packet length - use the FULL UDP Packet Length here */
428 			0,				/* checksum */
429 			(u_char*)msg,			/* payload */
430 			pktLen,				/* payload size */
431 			pWrkrData->libnet_handle,	/* libnet handle */
432 			udp);				/* libnet id */
433 		if (udp == -1) {
434 			DBGPRINTF("omudpspoof: can't build UDP header: %s\n",
435 				libnet_geterror(pWrkrData->libnet_handle));
436 		}
437 
438 		ip = libnet_build_ipv4(
439 			LIBNET_IPV4_H+LIBNET_UDP_H+pktLen,	/* length */
440 			0,					/* TOS */
441 			ip_id,					/* IP ID */
442 			hdrOffs,				/* IP Frag */
443 			64,					/* TTL */
444 			IPPROTO_UDP,				/* protocol */
445 			0,					/* checksum */
446 			source_ip.sin_addr.s_addr,
447 			tempaddr->sin_addr.s_addr,
448 			NULL,					/* payload */
449 			0,					/* payload size */
450 			pWrkrData->libnet_handle,		/* libnet handle */
451 			ip);					/* libnet id */
452 		if (ip == -1) {
453 			DBGPRINTF("omudpspoof: can't build IP header: %s\n",
454 				libnet_geterror(pWrkrData->libnet_handle));
455 		}
456 
457 		// Disable UDP Checksum CALC if Packjet exceeds MTU
458 		if(len > (maxPktLen - LIBNET_UDP_H) ) {
459 			libnet_toggle_checksum(pWrkrData->libnet_handle, udp, 1);
460 		}
461 		/* Write it to the wire. */
462 		lsent = libnet_write(pWrkrData->libnet_handle);
463 		if(lsent != (int) (LIBNET_IPV4_H+LIBNET_UDP_H+pktLen)) {
464 			/* note: access to fd is a libnet internal. If a newer version of libnet does
465 			 * not expose that member, we should simply remove it. However, while it is there
466 			 * it is useful for consolidating with strace output.
467 			 */
468 			DBGPRINTF("omudpspoof: write error (total len %d): pktLen %d, sent %d, fd %d: %s\n",
469 				  (int) len, LIBNET_IPV4_H+LIBNET_UDP_H+pktLen, lsent, pWrkrData->libnet_handle->fd,
470 				  libnet_geterror(pWrkrData->libnet_handle));
471 			if(lsent != -1) {
472 				bSendSuccess = RSTRUE;
473 			}
474 		} else {
475 			bSendSuccess = RSTRUE;
476 		}
477 		msgOffs += pktLen;
478 
479 		/* We need to get rid of the UDP header to build the other fragments */
480 		libnet_clear_packet(pWrkrData->libnet_handle);
481 		ip = LIBNET_PTAG_INITIALIZER;
482 		while(len > msgOffs ) { /* loop until all payload is sent */
483 			/* check if there will be more fragments */
484 			if((len - msgOffs) > maxPktLen) {
485 				/* In IP's eyes, the UDP header in the first packet
486 				* needs to be in the offset, so we add its size to
487 				* the payload offset here */
488 				hdrOffs = IP_MF + (msgOffs + LIBNET_UDP_H)/8;
489 				pktLen = maxPktLen;
490 			} else {
491 				/* See above */
492 				hdrOffs = (msgOffs + LIBNET_UDP_H)/8;
493 				pktLen = len - msgOffs;
494 			}
495 			DBGPRINTF("omudpspoof: stage 2: MF:%d, hdrOffs %d, pktLen %d\n",
496 				  (hdrOffs & IP_MF) >> 13, (hdrOffs & 0x1FFF) << 3, pktLen);
497 			ip = libnet_build_ipv4(
498 				LIBNET_IPV4_H + pktLen,         /* length */
499 				0,				/* TOS */
500 				ip_id,				/* IP ID */
501 				hdrOffs,			/* IP Frag */
502 				64,				/* TTL */
503 				IPPROTO_UDP,			/* protocol */
504 				0,				/* checksum */
505 				source_ip.sin_addr.s_addr,
506 				tempaddr->sin_addr.s_addr,
507 				(uint8_t*)(msg+msgOffs),	/* payload */
508 				pktLen, 			/* payload size */
509 				pWrkrData->libnet_handle,		/* libnet handle */
510 				ip);				/* libnet id */
511 			if (ip == -1) {
512 				DBGPRINTF("omudpspoof: can't build IP fragment header: %s\n",
513 					libnet_geterror(pWrkrData->libnet_handle));
514 			}
515 			/* Write it to the wire. */
516 			lsent = libnet_write(pWrkrData->libnet_handle);
517 			if(lsent != (int) (LIBNET_IPV4_H+pktLen)) {
518 				DBGPRINTF("omudpspoof: fragment write error len %d, sent %d: %s\n",
519 					  (int) (LIBNET_IPV4_H+LIBNET_UDP_H+len), lsent,
520 						libnet_geterror(pWrkrData->libnet_handle));
521 				bSendSuccess = RSFALSE;
522 				continue;
523 			}
524 			msgOffs += pktLen;
525 		}
526 	}
527 
528 finalize_it:
529 	if(iRet != RS_RET_OK) {
530 		if(pWrkrData->libnet_handle != NULL) {
531 			libnet_destroy(pWrkrData->libnet_handle);
532 			pWrkrData->libnet_handle = NULL;
533 		}
534 	}
535 	if(bNeedUnlock) {
536 		d_pthread_mutex_unlock(&mutLibnet);
537 	}
538 	RETiRet;
539 }
540 #ifdef _GNUC__
541 #pragma GCC diagnostic pop
542 #endif
543 
544 /* try to resume connection if it is not ready
545  * rgerhards, 2007-08-02
546  */
doTryResume(wrkrInstanceData_t * pWrkrData)547 static rsRetVal doTryResume(wrkrInstanceData_t *pWrkrData)
548 {
549 	int iErr;
550 	struct addrinfo *res;
551 	struct addrinfo hints;
552 	instanceData *pData;
553 	DEFiRet;
554 
555 	if(pWrkrData->pSockArray != NULL)
556 		FINALIZE;
557 	pData = pWrkrData->pData;
558 
559 	if(pWrkrData->libnet_handle == NULL) {
560 		/* Initialize the libnet library.  Root priviledges are required.
561 		 * this initializes a IPv4 socket to use for forging UDP packets.
562 		 */
563 		pWrkrData->libnet_handle = libnet_init(
564 		    LIBNET_RAW4,                            /* injection type */
565 		    NULL,                                   /* network interface */
566 		    pWrkrData->errbuf);                     /* errbuf */
567 
568 		if(pWrkrData->libnet_handle == NULL) {
569 			if(pData->bReportLibnetInitErr) {
570 				LogError(0, RS_RET_ERR_LIBNET_INIT, "omudpsoof: error "
571 				                "initializing libnet - are you running as root?");
572 				pData->bReportLibnetInitErr = 0;
573 			}
574 			ABORT_FINALIZE(RS_RET_ERR_LIBNET_INIT);
575 		}
576 	}
577 	DBGPRINTF("omudpspoof: libnit_init() ok\n");
578 	pData->bReportLibnetInitErr = 1;
579 
580 	/* The remote address is not yet known and needs to be obtained */
581 	DBGPRINTF("omudpspoof trying resume for '%s'\n", pData->host);
582 	memset(&hints, 0, sizeof(hints));
583 	/* port must be numeric, because config file syntax requires this */
584 	hints.ai_flags = AI_NUMERICSERV;
585 	hints.ai_family = glbl.GetDefPFFamily();
586 	hints.ai_socktype = SOCK_DGRAM;
587 	if((iErr = (getaddrinfo((char*)pData->host, (char*)getFwdPt(pData), &hints, &res))) != 0) {
588 		DBGPRINTF("could not get addrinfo for hostname '%s':'%s': %d%s\n",
589 			  pData->host, getFwdPt(pData), iErr, gai_strerror(iErr));
590 		ABORT_FINALIZE(RS_RET_SUSPENDED);
591 	}
592 	DBGPRINTF("%s found, resuming.\n", pData->host);
593 	pWrkrData->f_addr = res;
594 	pWrkrData->pSockArray = net.create_udp_socket((uchar*)pData->host, NULL, 0, 0, 0, 0, NULL);
595 
596 finalize_it:
597 	if(iRet != RS_RET_OK) {
598 		if(pWrkrData->f_addr != NULL) {
599 			freeaddrinfo(pWrkrData->f_addr);
600 			pWrkrData->f_addr = NULL;
601 		}
602 		iRet = RS_RET_SUSPENDED;
603 	}
604 
605 	RETiRet;
606 }
607 
608 BEGINtryResume
609 CODESTARTtryResume
610 	iRet = doTryResume(pWrkrData);
611 ENDtryResume
612 
613 BEGINdoAction
614 	char *psz; /* temporary buffering */
615 	unsigned l;
616 	int iMaxLine;
617 CODESTARTdoAction
618 	CHKiRet(doTryResume(pWrkrData));
619 
620 	DBGPRINTF(" %s:%s/omudpspoof, src '%s', msg strt '%.256s'\n", pWrkrData->pData->host,
621 		  getFwdPt(pWrkrData->pData), ppString[1], ppString[0]);
622 
623 	iMaxLine = glbl.GetMaxLine();
624 	psz = (char*) ppString[0];
625 	l = strlen((char*) psz);
626 	if((int) l > iMaxLine)
627 		l = iMaxLine;
628 
629 	CHKiRet(UDPSend(pWrkrData, ppString[1], psz, l));
630 
631 finalize_it:
632 ENDdoAction
633 
634 
635 static void
setInstParamDefaults(instanceData * pData)636 setInstParamDefaults(instanceData *pData)
637 {
638 	pData->tplName = NULL;
639 	pData->sourcePortStart = DFLT_SOURCE_PORT_START;
640 	pData->sourcePortEnd = DFLT_SOURCE_PORT_END;
641 	pData->host = NULL;
642 	pData->port = NULL;
643 	pData->sourceTpl = (uchar*) strdup("RSYSLOG_omudpspoofDfltSourceTpl");
644 	pData->mtu = 1500;
645 }
646 
647 BEGINnewActInst
648 	struct cnfparamvals *pvals;
649 	uchar *tplToUse;
650 	int i;
651 CODESTARTnewActInst
652 	DBGPRINTF("newActInst (omudpspoof)\n");
653 
654 	pvals = nvlstGetParams(lst, &actpblk, NULL);
655 	if(pvals == NULL) {
656 		LogError(0, RS_RET_MISSING_CNFPARAMS, "omudpspoof: mandatory "
657 		                "parameters missing");
658 		ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
659 	}
660 
661 	if(Debug) {
662 		dbgprintf("action param blk in omudpspoof:\n");
663 		cnfparamsPrint(&actpblk, pvals);
664 	}
665 
666 	CHKiRet(createInstance(&pData));
667 	setInstParamDefaults(pData);
668 
669 	for(i = 0 ; i < actpblk.nParams ; ++i) {
670 		if(!pvals[i].bUsed)
671 			continue;
672 		if(!strcmp(actpblk.descr[i].name, "target")) {
673 			pData->host = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
674 		} else if(!strcmp(actpblk.descr[i].name, "port")) {
675 			pData->port = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
676 		} else if(!strcmp(actpblk.descr[i].name, "sourcetemplate")) {
677 			free(pData->sourceTpl);
678 			pData->sourceTpl = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
679 		} else if(!strcmp(actpblk.descr[i].name, "sourceport.start")) {
680 			pData->sourcePortStart = (int) pvals[i].val.d.n;
681 		} else if(!strcmp(actpblk.descr[i].name, "sourceport.end")) {
682 			pData->sourcePortEnd = pvals[i].val.d.n;
683 		} else if(!strcmp(actpblk.descr[i].name, "mtu")) {
684 			pData->mtu = pvals[i].val.d.n;
685 		} else if(!strcmp(actpblk.descr[i].name, "template")) {
686 			pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
687 		} else {
688 			DBGPRINTF("omudpspoof: program error, non-handled "
689 			  "param '%s'\n", actpblk.descr[i].name);
690 		}
691 	}
692 	CODE_STD_STRING_REQUESTnewActInst(2)
693 
694 	tplToUse = ustrdup((pData->tplName == NULL) ? getDfltTpl() : pData->tplName);
695 	CHKiRet(OMSRsetEntry(*ppOMSR, 0, tplToUse, OMSR_NO_RQD_TPL_OPTS));
696 	CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->sourceTpl), OMSR_NO_RQD_TPL_OPTS));
697 
698 CODE_STD_FINALIZERnewActInst
699 	cnfparamvalsDestruct(pvals, &actpblk);
700 ENDnewActInst
701 
702 
703 BEGINparseSelectorAct
704 	uchar *sourceTpl;
705 CODESTARTparseSelectorAct
706 CODE_STD_STRING_REQUESTparseSelectorAct(2)
707 	/* first check if this config line is actually for us */
708 	if(strncmp((char*) p, ":omudpspoof:", sizeof(":omudpspoof:") - 1)) {
709 		ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
710 	}
711 
712 	/* ok, if we reach this point, we have something for us */
713 	p += sizeof(":omudpspoof:") - 1; /* eat indicator sequence  (-1 because of '\0'!) */
714 	CHKiRet(createInstance(&pData));
715 
716 	sourceTpl = (cs.pszSourceNameTemplate == NULL) ? UCHAR_CONSTANT("RSYSLOG_omudpspoofDfltSourceTpl")
717 						    : cs.pszSourceNameTemplate;
718 
719 	if(cs.pszTargetHost == NULL) {
720 		LogError(0, NO_ERRCODE, "No $ActionOMUDPSpoofTargetHost given, can not continue "
721 			"with this action.");
722 		ABORT_FINALIZE(RS_RET_HOST_NOT_SPECIFIED);
723 	}
724 
725 	/* fill instance properties */
726 	CHKmalloc(pData->host = ustrdup(cs.pszTargetHost));
727 	if(cs.pszTargetPort == NULL)
728 		pData->port = NULL;
729 	else
730 		CHKmalloc(pData->port = ustrdup(cs.pszTargetPort));
731 	CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(sourceTpl), OMSR_NO_RQD_TPL_OPTS));
732 	pData->sourcePortStart = cs.iSourcePortStart;
733 	pData->sourcePortEnd = cs.iSourcePortEnd;
734 
735 	/* process template */
736 	CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS,
737 		(cs.tplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.tplName));
738 
739 CODE_STD_FINALIZERparseSelectorAct
740 ENDparseSelectorAct
741 
742 
743 /* a common function to free our configuration variables - used both on exit
744  * and on $ResetConfig processing. -- rgerhards, 2008-05-16
745  */
746 static void
freeConfigVars(void)747 freeConfigVars(void)
748 {
749 	free(cs.tplName);
750 	cs.tplName = NULL;
751 	free(cs.pszTargetHost);
752 	cs.pszTargetHost = NULL;
753 	free(cs.pszTargetPort);
754 	cs.pszTargetPort = NULL;
755 }
756 
757 
758 BEGINmodExit
759 CODESTARTmodExit
760 	/* destroy the libnet state needed for forged UDP sources */
761 	pthread_mutex_destroy(&mutLibnet);
762 	/* release what we no longer need */
763 	objRelease(glbl, CORE_COMPONENT);
764 	objRelease(net, LM_NET_FILENAME);
765 	freeConfigVars();
766 ENDmodExit
767 
768 
769 BEGINqueryEtryPt
770 CODESTARTqueryEtryPt
771 CODEqueryEtryPt_STD_OMOD_QUERIES
772 CODEqueryEtryPt_STD_OMOD8_QUERIES
773 CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES
774 CODEqueryEtryPt_STD_CONF2_QUERIES
775 CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
776 ENDqueryEtryPt
777 
778 
779 /* Reset config variables for this module to default values.
780  * rgerhards, 2008-03-28
781  */
resetConfigVariables(uchar * pp,void * pVal)782 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
783 {
784 	freeConfigVars();
785 	/* we now must reset all non-string values */
786 	cs.iSourcePortStart = DFLT_SOURCE_PORT_START;
787 	cs.iSourcePortEnd = DFLT_SOURCE_PORT_END;
788 	return RS_RET_OK;
789 }
790 
791 
792 BEGINmodInit()
793 CODESTARTmodInit
794 INITLegCnfVars
795 	*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
796 CODEmodInit_QueryRegCFSLineHdlr
797 	CHKiRet(objUse(glbl, CORE_COMPONENT));
798 	CHKiRet(objUse(net,LM_NET_FILENAME));
799 
800 	pthread_mutex_init(&mutLibnet, NULL);
801 
802 	CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofdefaulttemplate", 0, eCmdHdlrGetWord,
803 	setLegacyDfltTpl, NULL, NULL));
804 	CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourcenametemplate", 0, eCmdHdlrGetWord, NULL,
805 	&cs.pszSourceNameTemplate, NULL));
806 	CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargethost", 0, eCmdHdlrGetWord, NULL,
807 	&cs.pszTargetHost, NULL));
808 	CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargetport", 0, eCmdHdlrGetWord, NULL,
809 	&cs.pszTargetPort, NULL));
810 	CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportstart", 0, eCmdHdlrInt, NULL,
811 	&cs.iSourcePortStart, NULL));
812 	CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportend", 0, eCmdHdlrInt, NULL,
813 	&cs.iSourcePortEnd, NULL));
814 	CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables,
815 	NULL, STD_LOADABLE_MODULE_ID));
816 ENDmodInit
817 
818 /* vim:set ai:
819  */
820