diff options
-rw-r--r-- | omfwd.c | 198 | ||||
-rw-r--r-- | omfwd.h | 1 | ||||
-rw-r--r-- | syslogd.c | 171 |
3 files changed, 200 insertions, 170 deletions
@@ -37,6 +37,10 @@ #include <fnmatch.h> #include <assert.h> #include <errno.h> +#include <ctype.h> +#ifdef USE_PTHREADS +#include <pthread.h> +#endif #include "rsyslog.h" #include "syslogd.h" #include "syslogd-types.h" @@ -273,6 +277,200 @@ rsRetVal modInitFwd(int iIFVersRequested __attribute__((unused)), int *ipIFVersP *pQueryEtryPt = queryEtryPt; return RS_RET_OK; } + + +/* try to process a selector action line. Checks if the action + * applies to this module and, if so, processed it. If not, it + * is left untouched. The driver will then call another module + */ +rsRetVal parseSelectorActFwd(uchar **pp, selector_t *f) +{ + uchar *p, *q; + int i; + int error; + int bErr; + rsRetVal iRet = RS_RET_CONFLINE_PROCESSED; + struct addrinfo hints, *res; + char szTemplateName[128]; + + assert(pp != NULL); + assert(f != NULL); + + p = *pp; + + switch (*p) + { + case '@': + ++p; /* eat '@' */ + if(*p == '@') { /* indicator for TCP! */ + f->f_un.f_forw.protocol = FORW_TCP; + ++p; /* eat this '@', too */ + /* in this case, we also need a mutex... */ +# ifdef USE_PTHREADS + pthread_mutex_init(&f->f_un.f_forw.mtxTCPSend, 0); +# endif + } else { + f->f_un.f_forw.protocol = FORW_UDP; + } + /* we are now after the protocol indicator. Now check if we should + * use compression. We begin to use a new option format for this: + * @(option,option)host:port + * The first option defined is "z[0..9]" where the digit indicates + * the compression level. If it is not given, 9 (best compression) is + * assumed. An example action statement might be: + * @@(z5,o)127.0.0.1:1400 + * Which means send via TCP with medium (5) compresion (z) to the local + * host on port 1400. The '0' option means that octet-couting (as in + * IETF I-D syslog-transport-tls) is to be used for framing (this option + * applies to TCP-based syslog only and is ignored when specified with UDP). + * That is not yet implemented. + * rgerhards, 2006-12-07 + */ + if(*p == '(') { + /* at this position, it *must* be an option indicator */ + do { + ++p; /* eat '(' or ',' (depending on when called) */ + /* check options */ + if(*p == 'z') { /* compression */ +# ifdef USE_NETZIP + ++p; /* eat */ + if(isdigit((int) *p)) { + int iLevel; + iLevel = *p - '0'; + ++p; /* eat */ + f->f_un.f_forw.compressionLevel = iLevel; + } else { + logerrorInt("Invalid compression level '%c' specified in " + "forwardig action - NOT turning on compression.", + *p); + } +# else + logerror("Compression requested, but rsyslogd is not compiled " + "with compression support - request ignored."); +# endif /* #ifdef USE_NETZIP */ + } else if(*p == 'o') { /* octet-couting based TCP framing? */ + ++p; /* eat */ + /* no further options settable */ + f->f_un.f_forw.tcp_framing = TCP_FRAMING_OCTET_COUNTING; + } else { /* invalid option! Just skip it... */ + logerrorInt("Invalid option %c in forwarding action - ignoring.", *p); + ++p; /* eat invalid option */ + } + /* the option processing is done. We now do a generic skip + * to either the next option or the end of the option + * block. + */ + while(*p && *p != ')' && *p != ',') + ++p; /* just skip it */ + } while(*p && *p == ','); /* Attention: do.. while() */ + if(*p == ')') + ++p; /* eat terminator, on to next */ + else + /* we probably have end of string - leave it for the rest + * of the code to handle it (but warn the user) + */ + logerror("Option block not terminated in forwarding action."); + } + /* extract the host first (we do a trick - we replace the ';' or ':' with a '\0') + * now skip to port and then template name. rgerhards 2005-07-06 + */ + for(q = p ; *p && *p != ';' && *p != ':' ; ++p) + /* JUST SKIP */; + + f->f_un.f_forw.port = NULL; + if(*p == ':') { /* process port */ + uchar * tmp; + + *p = '\0'; /* trick to obtain hostname (later)! */ + tmp = ++p; + for(i=0 ; *p && isdigit((int) *p) ; ++p, ++i) + /* SKIP AND COUNT */; + f->f_un.f_forw.port = malloc(i + 1); + if(f->f_un.f_forw.port == NULL) { + logerror("Could not get memory to store syslog forwarding port, " + "using default port, results may not be what you intend\n"); + /* we leave f_forw.port set to NULL, this is then handled by + * getFwdSyslogPt(). + */ + } else { + memcpy(f->f_un.f_forw.port, tmp, i); + *(f->f_un.f_forw.port + i) = '\0'; + } + } + + /* now skip to template */ + bErr = 0; + while(*p && *p != ';') { + if(*p && *p != ';' && !isspace((int) *p)) { + if(bErr == 0) { /* only 1 error msg! */ + bErr = 1; + errno = 0; + logerror("invalid selector line (port), probably not doing " + "what was intended"); + } + } + ++p; + } + + if(*p == ';') { + *p = '\0'; /* trick to obtain hostname (later)! */ + ++p; + /* Now look for the template! */ + cflineParseTemplateName(&p, szTemplateName, + sizeof(szTemplateName) / sizeof(char)); + } else + szTemplateName[0] = '\0'; + if(szTemplateName[0] == '\0') { + /* we do not have a template, so let's use the default */ + strcpy(szTemplateName, " StdFwdFmt"); + } + + /* first set the f->f_type */ + strcpy(f->f_un.f_forw.f_hname, (char*) q); + memset(&hints, 0, sizeof(hints)); + /* port must be numeric, because config file syntax requests this */ + hints.ai_flags = AI_NUMERICSERV; + hints.ai_family = family; + hints.ai_socktype = f->f_un.f_forw.protocol == FORW_UDP ? SOCK_DGRAM : SOCK_STREAM; + f->doAction = doActionFwd; + if( (error = getaddrinfo(f->f_un.f_forw.f_hname, getFwdSyslogPt(f), &hints, &res)) != 0) { + f->f_type = F_FORW_UNKN; + f->f_prevcount = INET_RETRY_MAX; + f->f_un.f_forw.ttSuspend = time(NULL); + } else { + f->f_type = F_FORW; + f->f_un.f_forw.f_addr = res; + } + + /* then try to find the template and re-set f_type to UNUSED + * if it can not be found. */ + cflineSetTemplateAndIOV(f, szTemplateName); + if(f->f_type == F_UNUSED) + /* safety measure to make sure we have a valid + * selector line before we continue down below. + * rgerhards 2005-07-29 + */ + break; + + dprintf("forwarding host: '%s:%s/%s' template '%s'\n", q, getFwdSyslogPt(f), + f->f_un.f_forw.protocol == FORW_UDP ? "udp" : "tcp", + szTemplateName); + /* + * Otherwise the host might be unknown due to an + * inaccessible nameserver (perhaps on the same + * host). We try to get the ip number later, like + * FORW_SUSP. + */ + default: + iRet = RS_RET_CONFLINE_UNPROCESSED; + break; + } + + if(iRet == RS_RET_CONFLINE_PROCESSED) + *pp = p; + return iRet; +} + #endif /* #ifdef SYSLOG_INET */ /* * vi:set ai: @@ -27,6 +27,7 @@ /* prototypes */ int doActionFwd(selector_t *f); rsRetVal modInitFwd(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)()); +rsRetVal parseSelectorActFwd(uchar **pp, selector_t *f); #endif /* #ifndef OMFWD_H_INCLUDED */ /* @@ -5037,16 +5037,8 @@ static rsRetVal cflineProcessTagSelector(uchar **pline) static rsRetVal cfline(char *line, register selector_t *f) { uchar *p; - register uchar *q; - register int i; int syncfile; rsRetVal iRet; -#ifdef SYSLOG_INET - struct addrinfo hints, *res; - int error; - int bErr; -#endif - char szTemplateName[128]; #ifdef WITH_DB int iMySQLPropErr = 0; #endif @@ -5105,168 +5097,7 @@ static rsRetVal cfline(char *line, register selector_t *f) switch (*p) { case '@': -#ifdef SYSLOG_INET - ++p; /* eat '@' */ - if(*p == '@') { /* indicator for TCP! */ - f->f_un.f_forw.protocol = FORW_TCP; - ++p; /* eat this '@', too */ - /* in this case, we also need a mutex... */ -# ifdef USE_PTHREADS - pthread_mutex_init(&f->f_un.f_forw.mtxTCPSend, 0); -# endif - } else { - f->f_un.f_forw.protocol = FORW_UDP; - } - /* we are now after the protocol indicator. Now check if we should - * use compression. We begin to use a new option format for this: - * @(option,option)host:port - * The first option defined is "z[0..9]" where the digit indicates - * the compression level. If it is not given, 9 (best compression) is - * assumed. An example action statement might be: - * @@(z5,o)127.0.0.1:1400 - * Which means send via TCP with medium (5) compresion (z) to the local - * host on port 1400. The '0' option means that octet-couting (as in - * IETF I-D syslog-transport-tls) is to be used for framing (this option - * applies to TCP-based syslog only and is ignored when specified with UDP). - * That is not yet implemented. - * rgerhards, 2006-12-07 - */ - if(*p == '(') { - /* at this position, it *must* be an option indicator */ - do { - ++p; /* eat '(' or ',' (depending on when called) */ - /* check options */ - if(*p == 'z') { /* compression */ -# ifdef USE_NETZIP - ++p; /* eat */ - if(isdigit((int) *p)) { - int iLevel; - iLevel = *p - '0'; - ++p; /* eat */ - f->f_un.f_forw.compressionLevel = iLevel; - } else { - logerrorInt("Invalid compression level '%c' specified in " - "forwardig action - NOT turning on compression.", - *p); - } -# else - logerror("Compression requested, but rsyslogd is not compiled " - "with compression support - request ignored."); -# endif /* #ifdef USE_NETZIP */ - } else if(*p == 'o') { /* octet-couting based TCP framing? */ - ++p; /* eat */ - /* no further options settable */ - f->f_un.f_forw.tcp_framing = TCP_FRAMING_OCTET_COUNTING; - } else { /* invalid option! Just skip it... */ - logerrorInt("Invalid option %c in forwarding action - ignoring.", *p); - ++p; /* eat invalid option */ - } - /* the option processing is done. We now do a generic skip - * to either the next option or the end of the option - * block. - */ - while(*p && *p != ')' && *p != ',') - ++p; /* just skip it */ - } while(*p && *p == ','); /* Attention: do.. while() */ - if(*p == ')') - ++p; /* eat terminator, on to next */ - else - /* we probably have end of string - leave it for the rest - * of the code to handle it (but warn the user) - */ - logerror("Option block not terminated in forwarding action."); - } - /* extract the host first (we do a trick - we replace the ';' or ':' with a '\0') - * now skip to port and then template name. rgerhards 2005-07-06 - */ - for(q = p ; *p && *p != ';' && *p != ':' ; ++p) - /* JUST SKIP */; - - f->f_un.f_forw.port = NULL; - if(*p == ':') { /* process port */ - uchar * tmp; - - *p = '\0'; /* trick to obtain hostname (later)! */ - tmp = ++p; - for(i=0 ; *p && isdigit((int) *p) ; ++p, ++i) - /* SKIP AND COUNT */; - f->f_un.f_forw.port = malloc(i + 1); - if(f->f_un.f_forw.port == NULL) { - logerror("Could not get memory to store syslog forwarding port, " - "using default port, results may not be what you intend\n"); - /* we leave f_forw.port set to NULL, this is then handled by - * getFwdSyslogPt(). - */ - } else { - memcpy(f->f_un.f_forw.port, tmp, i); - *(f->f_un.f_forw.port + i) = '\0'; - } - } - - /* now skip to template */ - bErr = 0; - while(*p && *p != ';') { - if(*p && *p != ';' && !isspace((int) *p)) { - if(bErr == 0) { /* only 1 error msg! */ - bErr = 1; - errno = 0; - logerror("invalid selector line (port), probably not doing " - "what was intended"); - } - } - ++p; - } - - if(*p == ';') { - *p = '\0'; /* trick to obtain hostname (later)! */ - ++p; - /* Now look for the template! */ - cflineParseTemplateName(&p, szTemplateName, - sizeof(szTemplateName) / sizeof(char)); - } else - szTemplateName[0] = '\0'; - if(szTemplateName[0] == '\0') { - /* we do not have a template, so let's use the default */ - strcpy(szTemplateName, " StdFwdFmt"); - } - - /* first set the f->f_type */ - strcpy(f->f_un.f_forw.f_hname, (char*) q); - memset(&hints, 0, sizeof(hints)); - /* port must be numeric, because config file syntax requests this */ - hints.ai_flags = AI_NUMERICSERV; - hints.ai_family = family; - hints.ai_socktype = f->f_un.f_forw.protocol == FORW_UDP ? SOCK_DGRAM : SOCK_STREAM; - f->doAction = doActionFwd; - if( (error = getaddrinfo(f->f_un.f_forw.f_hname, getFwdSyslogPt(f), &hints, &res)) != 0) { - f->f_type = F_FORW_UNKN; - f->f_prevcount = INET_RETRY_MAX; - f->f_un.f_forw.ttSuspend = time(NULL); - } else { - f->f_type = F_FORW; - f->f_un.f_forw.f_addr = res; - } - - /* then try to find the template and re-set f_type to UNUSED - * if it can not be found. */ - cflineSetTemplateAndIOV(f, szTemplateName); - if(f->f_type == F_UNUSED) - /* safety measure to make sure we have a valid - * selector line before we continue down below. - * rgerhards 2005-07-29 - */ - break; - - dprintf("forwarding host: '%s:%s/%s' template '%s'\n", q, getFwdSyslogPt(f), - f->f_un.f_forw.protocol == FORW_UDP ? "udp" : "tcp", - szTemplateName); - /* - * Otherwise the host might be unknown due to an - * inaccessible nameserver (perhaps on the same - * host). We try to get the ip number later, like - * FORW_SUSP. - */ -#endif /* #ifdef SYSLOG_INET */ + parseSelectorActFwd(&p, f); break; case '$': |