From d6f180ec175f3660e36478b9e32ec6ca73e33604 Mon Sep 17 00:00:00 2001 From: Jan Gerhards Date: Fri, 10 Feb 2017 14:30:01 +0100 Subject: [PATCH] add num2ipv4 function and test closes https://github.com/rsyslog/rsyslog/issues/1322 testbench: add testcase empty string for num2ipv4 function see https://github.com/rsyslog/rsyslog/issues/1412 --- grammar/rainerscript.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 4 +- tests/Makefile.am | 2 + tests/rscript_num2ipv4.sh | 41 +++++++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100755 tests/rscript_num2ipv4.sh diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 30af5e7b..2f0fc2d8 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1710,6 +1710,113 @@ doRandomGen(struct svar *__restrict__ const sourceVal) { return x % max; } +static long long +ipv42num(char *str) +{ + unsigned num[4] = {0, 0, 0, 0}; + long long value = -1; + size_t len = strlen(str); + int cyc = 0; + int prevdot = 0; + int startblank = 0; + int endblank = 0; + DBGPRINTF("rainerscript: (ipv42num) arg: '%s'\n", str); + for(unsigned int i = 0 ; i < len ; i++) { + switch(str[i]){ + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if(endblank == 1){ + DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (invalid space(1))\n"); + goto done; + } + prevdot = 0; + startblank = 0; + DBGPRINTF("rainerscript: (ipv42num) cycle: %d\n", cyc); + num[cyc] = num[cyc]*10+(str[i]-'0'); + break; + case ' ': + prevdot = 0; + if(i == 0 || startblank == 1){ + startblank = 1; + break; + } + else{ + endblank = 1; + break; + } + case '.': + if(endblank == 1){ + DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (inalid space(2))\n"); + goto done; + } + startblank = 0; + if(prevdot == 1){ + DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (two dots after one another)\n"); + goto done; + } + prevdot = 1; + cyc++; + if(cyc > 3){ + DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (too many dots)\n"); + goto done; + } + break; + default: + DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (invalid charakter)\n"); + goto done; + } + } + if(cyc != 3){ + DBGPRINTF("rainerscript: (ipv42num) error: wrong IP-Address format (wrong number of dots)\n"); + goto done; + } + value = num[0]*256*256*256+num[1]*256*256+num[2]*256+num[3]; +done: + DBGPRINTF("rainerscript: (ipv42num): return value:'%lld'\n",value); + return(value); +} + + +static es_str_t* +num2ipv4(struct svar *__restrict__ const sourceVal) { + int success = 0; + int numip[4]; + char str[16]; + size_t len; + es_str_t *estr; + long long num = var2Number(sourceVal, &success); + DBGPRINTF("rainrescript: (num2ipv4) var2Number output: '%lld\n'", num); + if (! success) { + DBGPRINTF("rainerscript: (num2ipv4) couldn't access number\n"); + len = snprintf(str, 16, "-1"); + goto done; + } + if(num < 0 || num > 4294967295) { + DBGPRINTF("rainerscript: (num2ipv4) invalid number(too big/negative); does not represent IPv4 address\n"); + len = snprintf(str, 16, "-1"); + goto done; + } + for(int i = 0 ; i < 4 ; i++){ + numip[i] = num % 256; + num = num / 256; + } + DBGPRINTF("rainerscript: (num2ipv4) Numbers: 1:'%d' 2:'%d' 3:'%d' 4:'%d'\n", numip[0], numip[1], numip[2], numip[3]); + len = snprintf(str, 16, "%d.%d.%d.%d", numip[3], numip[2], numip[1], numip[0]); +done: + DBGPRINTF("rainerscript: (num2ipv4) ipv4-Address: %s, lengh: %zu\n", str, len); + estr = es_newStrFromCStr(str, len); + return(estr); +} + + /* Perform a function call. This has been moved out of cnfExprEval in order * to keep the code small and easier to maintain. */ @@ -1775,6 +1882,12 @@ doFuncCall(struct cnffunc *__restrict__ const func, struct svar *__restrict__ co ret->datatype = 'N'; varFreeMembers(&r[0]); break; + case CNFFUNC_NUM2IPV4: + cnfexprEval(func->expr[0], &r[0], usrptr); + ret->d.estr = num2ipv4(&r[0]); + ret->datatype = 'S'; + varFreeMembers(&r[0]); + break; case CNFFUNC_GETENV: /* note: the optimizer shall have replaced calls to getenv() * with a constant argument to a single string (once obtained via @@ -3958,6 +4071,8 @@ funcName2ID(es_str_t *fname, unsigned short nParams) GENERATE_FUNC("strlen", 1, CNFFUNC_STRLEN); } else if(FUNC_NAME("getenv")) { GENERATE_FUNC("getenv", 1, CNFFUNC_GETENV); + } else if(FUNC_NAME("num2ipv4")) { + GENERATE_FUNC("num2ipv4", 1, CNFFUNC_NUM2IPV4); } else if(FUNC_NAME("tolower")) { GENERATE_FUNC("tolower", 1, CNFFUNC_TOLOWER); } else if(FUNC_NAME("cstr")) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 7bac7566..0fdbdc72 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -232,7 +232,9 @@ enum cnffuncid { CNFFUNC_REPLACE, CNFFUNC_WRAP, CNFFUNC_RANDOM, - CNFFUNC_DYN_INC + CNFFUNC_DYN_INC, + CNFFUNC_IPV42NUM, + CNFFUNC_NUM2IPV4 }; struct cnffunc { diff --git a/tests/Makefile.am b/tests/Makefile.am index f792b44a..572c6250 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -206,6 +206,7 @@ TESTS += \ rscript_lt_var.sh \ rscript_ne.sh \ rscript_ne_var.sh \ + rscript_num2ipv4.sh \ empty-prop-comparison.sh \ rs_optimizer_pri.sh \ cee_simple.sh \ @@ -728,6 +729,7 @@ EXTRA_DIST= \ rscript_ne.sh \ testsuites/rscript_ne.conf \ rscript_ne_var.sh \ + rscript_num2ipv4.sh \ testsuites/rscript_ne_var.conf \ rscript_eq.sh \ testsuites/rscript_eq.conf \ diff --git a/tests/rscript_num2ipv4.sh b/tests/rscript_num2ipv4.sh new file mode 100755 index 00000000..6e0026a9 --- /dev/null +++ b/tests/rscript_num2ipv4.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# add 2017-02-09 by Jan Gerhards, released under ASL 2.0 +. $srcdir/diag.sh init +. $srcdir/diag.sh generate-conf +. $srcdir/diag.sh add-conf ' +module(load="../plugins/imtcp/.libs/imtcp") +input(type="imtcp" port="13514") + +set $!ip!v1 = num2ipv4("0"); +set $!ip!v2 = num2ipv4("1"); +set $!ip!v3 = num2ipv4("256"); +set $!ip!v4 = num2ipv4("65536"); +set $!ip!v5 = num2ipv4("16777216"); +set $!ip!v6 = num2ipv4("135"); +set $!ip!v7 = num2ipv4("16843009"); +set $!ip!v8 = num2ipv4("3777036554"); +set $!ip!v9 = num2ipv4("2885681153"); +set $!ip!v10 = num2ipv4("4294967295"); + +set $!ip!e1 = num2ipv4("a"); +set $!ip!e2 = num2ipv4("-123"); +set $!ip!e3 = num2ipv4("1725464567890"); +set $!ip!e4 = num2ipv4("4294967296"); +set $!ip!e5 = num2ipv4("2839."); +set $!ip!e6 = num2ipv4(""); + + +template(name="outfmt" type="string" string="%!ip%\n") +local4.* action(type="omfile" file="rsyslog.out.log" template="outfmt") +' +. $srcdir/diag.sh startup +. $srcdir/diag.sh tcpflood -m1 -y +. $srcdir/diag.sh shutdown-when-empty +. $srcdir/diag.sh wait-shutdown +echo '{ "v1": "0.0.0.0", "v2": "0.0.0.1", "v3": "0.0.1.0", "v4": "0.1.0.0", "v5": "1.0.0.0", "v6": "0.0.0.135", "v7": "1.1.1.1", "v8": "225.33.1.10", "v9": "172.0.0.1", "v10": "255.255.255.255", "e1": "-1", "e2": "-1", "e3": "-1", "e4": "-1", "e5": "-1", "e6": "-1" }' | cmp rsyslog.out.log +if [ ! $? -eq 0 ]; then + echo "invalid function output detected, rsyslog.out.log is:" + cat rsyslog.out.log + . $srcdir/diag.sh error-exit 1 +fi; +. $srcdir/diag.sh exit -- 2.12.2