summaryrefslogtreecommitdiffstats
path: root/plugins/mmanon/mmanon.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/mmanon/mmanon.c1375
1 files changed, 1375 insertions, 0 deletions
diff --git a/plugins/mmanon/mmanon.c b/plugins/mmanon/mmanon.c
new file mode 100644
index 0000000..811b763
--- /dev/null
+++ b/plugins/mmanon/mmanon.c
@@ -0,0 +1,1375 @@
+/* mmanon.c
+ * anonnymize IP addresses inside the syslog message part
+ *
+ * Copyright 2013 Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+#include "rsyslog.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include "conf.h"
+#include "syslogd-types.h"
+#include "srUtils.h"
+#include "template.h"
+#include "module-template.h"
+#include "errmsg.h"
+#include "parserif.h"
+#include "hashtable.h"
+
+
+
+MODULE_TYPE_OUTPUT
+MODULE_TYPE_NOKEEP
+MODULE_CNFNAME("mmanon")
+
+
+DEF_OMOD_STATIC_DATA
+
+/* config variables */
+
+// enumerator for the mode
+enum mode {ZERO, RANDOMINT, SIMPLE};
+
+union node {
+ struct {
+ union node* more;
+ union node* less;
+ } pointer;
+ struct {
+ char ip_high[16];
+ char ip_low[16];
+ } ips;
+};
+
+struct ipv6_int {
+ unsigned long long high;
+ unsigned long long low;
+ };
+/* define operation modes we have */
+#define SIMPLE_MODE 0 /* just overwrite */
+#define REWRITE_MODE 1 /* rewrite IP address, canoninized */
+typedef struct _instanceData {
+ struct {
+ sbool enable;
+ int8_t bits;
+ union node* Root;
+ int randConsis;
+ enum mode mode;
+ uchar replaceChar;
+ } ipv4;
+
+ struct {
+ sbool enable;
+ uint8_t bits;
+ enum mode anonmode;
+ int randConsis;
+ struct hashtable* hash;
+ } ipv6;
+
+ struct {
+ sbool enable;
+ uint8_t bits;
+ enum mode anonmode;
+ int randConsis;
+ struct hashtable* hash;
+ } embeddedIPv4;
+} instanceData;
+
+typedef struct wrkrInstanceData {
+ instanceData *pData;
+ unsigned randstatus;
+} wrkrInstanceData_t;
+
+struct modConfData_s {
+ rsconf_t *pConf; /* our overall config object */
+};
+static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
+static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */
+
+
+/* tables for interfacing with the v6 config system */
+/* action (instance) parameters */
+static struct cnfparamdescr actpdescr[] = {
+ { "ipv4.enable", eCmdHdlrBinary, 0 },
+ { "ipv4.mode", eCmdHdlrGetWord, 0 },
+ { "mode", eCmdHdlrGetWord, 0 },
+ { "ipv4.bits", eCmdHdlrPositiveInt, 0 },
+ { "ipv4.replacechar", eCmdHdlrGetChar, 0},
+ { "replacementchar", eCmdHdlrGetChar, 0},
+ { "ipv6.enable", eCmdHdlrBinary, 0 },
+ { "ipv6.anonmode", eCmdHdlrGetWord, 0 },
+ { "ipv6.bits", eCmdHdlrPositiveInt, 0 },
+ { "embeddedipv4.enable", eCmdHdlrBinary, 0 },
+ { "embeddedipv4.anonmode", eCmdHdlrGetWord, 0 },
+ { "embeddedipv4.bits", eCmdHdlrPositiveInt, 0 }
+};
+static struct cnfparamblk actpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(actpdescr)/sizeof(struct cnfparamdescr),
+ actpdescr
+ };
+
+BEGINbeginCnfLoad
+CODESTARTbeginCnfLoad
+ loadModConf = pModConf;
+ pModConf->pConf = pConf;
+ENDbeginCnfLoad
+
+BEGINendCnfLoad
+CODESTARTendCnfLoad
+ENDendCnfLoad
+
+BEGINcheckCnf
+CODESTARTcheckCnf
+ENDcheckCnf
+
+BEGINactivateCnf
+CODESTARTactivateCnf
+ runModConf = pModConf;
+ENDactivateCnf
+
+BEGINfreeCnf
+CODESTARTfreeCnf
+ENDfreeCnf
+
+
+BEGINcreateInstance
+CODESTARTcreateInstance
+ENDcreateInstance
+
+BEGINcreateWrkrInstance
+CODESTARTcreateWrkrInstance
+ pWrkrData->randstatus = time(NULL);
+ENDcreateWrkrInstance
+
+
+BEGINisCompatibleWithFeature
+CODESTARTisCompatibleWithFeature
+ENDisCompatibleWithFeature
+
+
+static void
+delTree(union node* node, const int layer)
+{
+ if(node == NULL){
+ return;
+ }
+ if(layer == 31){
+ free(node);
+ } else {
+ delTree(node->pointer.more, layer + 1);
+ delTree(node->pointer.less, layer + 1);
+ free(node);
+ }
+}
+
+
+BEGINfreeInstance
+CODESTARTfreeInstance
+ delTree(pData->ipv4.Root, 0);
+ if(pData->ipv6.hash != NULL) {
+ hashtable_destroy(pData->ipv6.hash, 1);
+ }
+ if(pData->embeddedIPv4.hash != NULL) {
+ hashtable_destroy(pData->embeddedIPv4.hash, 1);
+ }
+ENDfreeInstance
+
+
+BEGINfreeWrkrInstance
+CODESTARTfreeWrkrInstance
+ENDfreeWrkrInstance
+
+
+static inline void
+setInstParamDefaults(instanceData *pData)
+{
+ pData->ipv4.enable = 1;
+ pData->ipv4.bits = 16;
+ pData->ipv4.Root = NULL;
+ pData->ipv4.randConsis = 0;
+ pData->ipv4.mode = ZERO;
+ pData->ipv4.replaceChar = 'x';
+
+ pData->ipv6.enable = 1;
+ pData->ipv6.bits = 96;
+ pData->ipv6.anonmode = ZERO;
+ pData->ipv6.randConsis = 0;
+ pData->ipv6.hash = NULL;
+
+ pData->embeddedIPv4.enable = 1;
+ pData->embeddedIPv4.bits = 96;
+ pData->embeddedIPv4.anonmode = ZERO;
+ pData->embeddedIPv4.randConsis = 0;
+ pData->embeddedIPv4.hash = NULL;
+}
+
+BEGINnewActInst
+ struct cnfparamvals *pvals;
+ int i;
+CODESTARTnewActInst
+ DBGPRINTF("newActInst (mmanon)\n");
+ if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
+ ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
+ }
+
+ CODE_STD_STRING_REQUESTnewActInst(1)
+ CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG));
+ CHKiRet(createInstance(&pData));
+ setInstParamDefaults(pData);
+
+ for(i = 0 ; i < actpblk.nParams ; ++i) {
+ if(!pvals[i].bUsed)
+ continue;
+ if(!strcmp(actpblk.descr[i].name, "ipv4.mode") || !strcmp(actpblk.descr[i].name, "mode")) {
+ if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"zero",
+ sizeof("zero")-1)) {
+ pData->ipv4.mode = ZERO;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"random",
+ sizeof("random")-1)) {
+ pData->ipv4.mode = RANDOMINT;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"simple",
+ sizeof("simple")-1) ||
+ !es_strbufcmp(pvals[i].val.d.estr, (uchar*)"rewrite",
+ sizeof("rewrite")-1)) {
+ pData->ipv4.mode = SIMPLE;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"random-consistent",
+ sizeof("random-consistent")-1)) {
+ pData->ipv4.mode = RANDOMINT;
+ pData->ipv4.randConsis = 1;
+ } else {
+ parser_errmsg("mmanon: configuration error, unknown option for ipv4.mode, "
+ "will use \"zero\"\n");
+ }
+ } else if(!strcmp(actpblk.descr[i].name, "ipv4.bits")) {
+ if((int8_t) pvals[i].val.d.n <= 32) {
+ pData->ipv4.bits = (int8_t) pvals[i].val.d.n;
+ } else {
+ pData->ipv4.bits = 32;
+ parser_errmsg("warning: invalid number of ipv4.bits (%d), corrected "
+ "to 32", (int) pvals[i].val.d.n);
+ }
+ } else if(!strcmp(actpblk.descr[i].name, "ipv4.enable")) {
+ pData->ipv4.enable = (int) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "ipv4.replacechar") || !strcmp(actpblk.descr[i].name,
+ "replacementchar")) {
+ uchar* tmp = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL);
+ pData->ipv4.replaceChar = tmp[0];
+ free(tmp);
+ } else if(!strcmp(actpblk.descr[i].name, "ipv6.enable")) {
+ pData->ipv6.enable = (int) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "ipv6.bits")) {
+ if((uint8_t) pvals[i].val.d.n <= 128) {
+ pData->ipv6.bits = (uint8_t) pvals[i].val.d.n;
+ } else {
+ pData->ipv6.bits = 128;
+ parser_errmsg("warning: invalid number of ipv6.bits (%d), corrected "
+ "to 128", (int) pvals[i].val.d.n);
+ }
+ } else if(!strcmp(actpblk.descr[i].name, "ipv6.anonmode")) {
+ if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"zero",
+ sizeof("zero")-1)) {
+ pData->ipv6.anonmode = ZERO;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"random",
+ sizeof("random")-1)) {
+ pData->ipv6.anonmode = RANDOMINT;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"random-consistent",
+ sizeof("random-consistent")-1)) {
+ pData->ipv6.anonmode = RANDOMINT;
+ pData->ipv6.randConsis = 1;
+ } else {
+ parser_errmsg("mmanon: configuration error, unknown option for "
+ "ipv6.anonmode, will use \"zero\"\n");
+ }
+ } else if(!strcmp(actpblk.descr[i].name, "embeddedipv4.enable")) {
+ pData->embeddedIPv4.enable = (int) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "embeddedipv4.bits")) {
+ if((uint8_t) pvals[i].val.d.n <= 128) {
+ pData->embeddedIPv4.bits = (uint8_t) pvals[i].val.d.n;
+ } else {
+ pData->embeddedIPv4.bits = 128;
+ parser_errmsg("warning: invalid number of embeddedipv4.bits (%d), "
+ "corrected to 128", (int) pvals[i].val.d.n);
+ }
+ } else if(!strcmp(actpblk.descr[i].name, "embeddedipv4.anonmode")) {
+ if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"zero",
+ sizeof("zero")-1)) {
+ pData->embeddedIPv4.anonmode = ZERO;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"random",
+ sizeof("random")-1)) {
+ pData->embeddedIPv4.anonmode = RANDOMINT;
+ } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"random-consistent",
+ sizeof("random-consistent")-1)) {
+ pData->embeddedIPv4.anonmode = RANDOMINT;
+ pData->embeddedIPv4.randConsis = 1;
+ } else {
+ parser_errmsg("mmanon: configuration error, unknown option for ipv6.anonmode, "
+ "will use \"zero\"\n");
+ }
+ } else {
+ parser_errmsg("mmanon: program error, non-handled "
+ "param '%s'\n", actpblk.descr[i].name);
+ }
+ }
+
+ int bHadBitsErr = 0;
+ if(pData->ipv4.mode == SIMPLE) {
+ if(pData->ipv4.bits < 8 && pData->ipv4.bits > -1) {
+ pData->ipv4.bits = 8;
+ bHadBitsErr = 1;
+ } else if(pData->ipv4.bits < 16 && pData->ipv4.bits > 8) {
+ pData->ipv4.bits = 16;
+ bHadBitsErr = 1;
+ } else if(pData->ipv4.bits < 24 && pData->ipv4.bits > 16) {
+ pData->ipv4.bits = 24;
+ bHadBitsErr = 1;
+ } else if((pData->ipv4.bits != 32 && pData->ipv4.bits > 24) || pData->ipv4.bits < 0) {
+ pData->ipv4.bits = 32;
+ bHadBitsErr = 1;
+ }
+ if(bHadBitsErr) {
+ LogError(0, RS_RET_INVLD_ANON_BITS,
+ "mmanon: invalid number of ipv4 bits "
+ "in simple mode, corrected to %d",
+ pData->ipv4.bits);
+ }
+ }
+
+CODE_STD_FINALIZERnewActInst
+ cnfparamvalsDestruct(pvals, &actpblk);
+ENDnewActInst
+
+
+BEGINdbgPrintInstInfo
+CODESTARTdbgPrintInstInfo
+ENDdbgPrintInstInfo
+
+
+BEGINtryResume
+CODESTARTtryResume
+ENDtryResume
+
+
+static int
+getHexVal(char c)
+{
+ if('0' <= c && c <= '9') {
+ return c - '0';
+ } else if('a' <= c && c <= 'f') {
+ return (c - 'a') + 10;
+ } else if('A' <= c && c <= 'F') {
+ return (c - 'A') + 10;
+ } else {
+ return -1;
+ }
+}
+
+
+/* returns 1 if valid IPv4 digit, 0 if not */
+static int
+isPosByte(const uchar *const __restrict__ buf,
+ const size_t buflen,
+ size_t *const __restrict__ nprocessed)
+{
+ int val = 0; /* Default means no byte found */
+ size_t i;
+ for(i = 0 ; i < buflen; i++) {
+ if('0' <= buf[i] && buf[i] <= '9') {
+ /* Maximum 3 digits for single IPv4 Number, we only copy up to 4 numbers
+ * but process forward to non digits */
+ if (i < 4) {
+ val = val*10 + buf[i]-'0';
+ }
+ } else
+ break;
+ }
+ *nprocessed = i;
+ /* Return 1 if more than 1 and less the 4 digits and between 0 and 255 */
+ if( i > 0 &&
+ i < 4 &&
+ (val >= 0 && val <= 255)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* 1 - is IPv4, 0 not */
+static int
+syntax_ipv4(const uchar *const __restrict__ buf,
+ const size_t buflen,
+ size_t *const __restrict__ nprocessed)
+{
+ size_t nproc = 0;
+ size_t i;
+ int r = 0;
+ if(isPosByte(buf, buflen, &i) == 0) {
+ goto done;
+ }
+ if(i >= buflen || buf[i] != '.') {
+ goto done;
+ }
+ i++;
+ if(isdigit(buf[i]) == 0 || isPosByte(buf+i, buflen-i, &nproc) == 0) {
+ goto done;
+ }
+ i += nproc;
+
+ if(i >= buflen || buf[i] != '.') {
+ goto done;
+ }
+ i++;
+ if(isdigit(buf[i]) == 0 || isPosByte(buf+i, buflen-i, &nproc) == 0) {
+ goto done;
+ }
+ i += nproc;
+
+ if(i >= buflen || buf[i] != '.') {
+ goto done;
+ }
+ i++;
+ if(isdigit(buf[i]) == 0 || isPosByte(buf+i, buflen-i, &nproc) == 0) {
+ goto done;
+ }
+ i += nproc;
+
+ *nprocessed = i;
+ r = 1;
+done:
+ return r;
+}
+
+
+static int
+isValidHexNum(const uchar *const __restrict__ buf,
+ const size_t buflen,
+ size_t *const __restrict__ nprocessed,
+ int handleDot)
+{
+ size_t idx = 0;
+ int cyc = 0;
+
+ while(idx < buflen) {
+ switch(buf[idx]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ cyc++;
+ (*nprocessed)++;
+ if(cyc == 5) {
+ goto done;
+ }
+ break;
+ case '.':
+ if(handleDot && cyc == 0) {
+ (*nprocessed)++;
+ cyc = -2;
+ }
+ goto done;
+ case ':':
+ if(cyc == 0) {
+ (*nprocessed)++;
+ cyc = -1;
+ }
+ goto done;
+ default:
+ goto done;
+ }
+ idx++;
+ }
+done:
+ return cyc;
+}
+
+
+static int
+syntax_ipv6(const uchar *const __restrict__ buf,
+ const size_t buflen,
+ size_t *const __restrict__ nprocessed)
+{
+ int lastSep = 0;
+ sbool hadAbbrev = 0;
+ sbool lastAbbrev = 0;
+ int ipParts = 0;
+ int numLen;
+ int isIP = 0;
+
+ while(*nprocessed < buflen) {
+ numLen = isValidHexNum(buf + *nprocessed, buflen - *nprocessed, nprocessed, 0);
+ if(numLen > 0 && numLen < 5) { //found a valid num
+ if((ipParts == 7 && hadAbbrev) || ipParts > 7) {
+ isIP = 0;
+ goto done;
+ }
+ if (ipParts == 0 && lastSep && !hadAbbrev) {
+ isIP = 0;
+ goto done;
+ }
+ lastSep = 0;
+ lastAbbrev = 0;
+ ipParts++;
+ } else if (numLen < 0) { //':'
+ if(lastSep) {
+ if(hadAbbrev) {
+ isIP = 0;
+ goto done;
+ } else {
+ hadAbbrev = 1;
+ lastAbbrev = 1;
+ }
+ }
+ lastSep = 1;
+ } else if (numLen == 5) { // maybe truncated with port
+ if(hadAbbrev && ipParts >= 2) {
+ isIP = 1;
+ /* we need to go back 6 chars:
+ * 5 digits plus leading ":" which designates port!
+ */
+ *nprocessed -= 6;
+ } else {
+ isIP = 0;
+ /* nprocessed need not be corrected - it's only used if isIP == 1 */
+ }
+ goto done;
+ } else { //no valid num
+ if(lastSep) {
+ if(lastAbbrev && ipParts < 8) {
+ isIP = 1;
+ goto done;
+ }
+ isIP = 0;
+ goto done;
+ }
+ if((ipParts == 8 && !hadAbbrev) || (ipParts < 8 && hadAbbrev)) {
+ isIP = 1;
+ goto done;
+ } else {
+ isIP = 0;
+ goto done;
+ }
+ }
+ if(ipParts == 8 && !hadAbbrev) {
+ isIP = 1;
+ goto done;
+ }
+ }
+
+ if((!lastSep && (ipParts == 8 && !hadAbbrev)) || (ipParts < 8 && hadAbbrev)) {
+ isIP = 1;
+ }
+
+done:
+ return isIP;
+}
+
+
+static unsigned
+ipv42num(const char *str)
+{
+ unsigned num[4] = {0, 0, 0, 0};
+ unsigned value = -1;
+ size_t len = strlen(str);
+ int cyc = 0;
+ for(unsigned 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':
+ num[cyc] = num[cyc]*10+(str[i]-'0');
+ break;
+ case '.':
+ cyc++;
+ break;
+ }
+ }
+
+ value = num[0]*256*256*256+num[1]*256*256+num[2]*256+num[3];
+ return(value);
+}
+
+
+static unsigned
+code_int(unsigned ip, wrkrInstanceData_t *pWrkrData){
+ unsigned random;
+ unsigned long long shiftIP_subst = ip;
+ // variable needed because shift operation of 32nd bit in unsigned does not work
+ switch(pWrkrData->pData->ipv4.mode) {
+ case ZERO:
+ shiftIP_subst = ((shiftIP_subst>>(pWrkrData->pData->ipv4.bits))<<(pWrkrData->pData->ipv4.bits));
+ return (unsigned)shiftIP_subst;
+ case RANDOMINT:
+ shiftIP_subst = ((shiftIP_subst>>(pWrkrData->pData->ipv4.bits))<<(pWrkrData->pData->ipv4.bits));
+ // multiply the random number between 0 and 1 with a mask of (2^n)-1:
+ random = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*
+ ((1ull<<(pWrkrData->pData->ipv4.bits))-1));
+ return (unsigned)shiftIP_subst + random;
+ case SIMPLE: //can't happen, since this case is caught at the start of anonipv4()
+ default:
+ LogError(0, RS_RET_INTERNAL_ERROR, "mmanon: unexpected code path reached in code_int function");
+ return 0;
+ }
+}
+
+
+static int
+num2ipv4(unsigned num, char *str) {
+ int numip[4];
+ size_t len;
+ for(int i = 0 ; i < 4 ; i++){
+ numip[i] = num % 256;
+ num = num / 256;
+ }
+ len = snprintf(str, 16, "%d.%d.%d.%d", numip[3], numip[2], numip[1], numip[0]);
+ return len;
+}
+
+
+static void
+getip(uchar *start, size_t end, char *address)
+{
+ size_t i;
+
+ for(i = 0; i < end; i++){
+ address[i] = *(start+i);
+ }
+ address[i] = '\0';
+}
+
+/* in case of error with malloc causing abort of function, the
+ * string at the target of address remains the same */
+static rsRetVal
+findip(char* address, wrkrInstanceData_t *pWrkrData)
+{
+ DEFiRet;
+ int i;
+ unsigned num;
+ union node* current;
+ union node* Last;
+ int MoreLess;
+ char* CurrentCharPtr;
+
+ current = pWrkrData->pData->ipv4.Root;
+ num = ipv42num(address);
+ for(i = 0; i < 31; i++){
+ if(pWrkrData->pData->ipv4.Root == NULL) {
+ CHKmalloc(current = (union node*)calloc(1, sizeof(union node)));
+ pWrkrData->pData->ipv4.Root = current;
+ }
+ Last = current;
+ if((num >> (31 - i)) & 1){
+ current = current->pointer.more;
+ MoreLess = 1;
+ } else {
+ current = current->pointer.less;
+ MoreLess = 0;
+ }
+ if(current == NULL){
+ CHKmalloc(current = (union node*)calloc(1, sizeof(union node)));
+ if(MoreLess == 1){
+ Last->pointer.more = current;
+ } else {
+ Last->pointer.less = current;
+ }
+ }
+ }
+ if(num & 1){
+ CurrentCharPtr = current->ips.ip_high;
+ } else {
+ CurrentCharPtr = current->ips.ip_low;
+ }
+ if(CurrentCharPtr[0] != '\0'){
+ strcpy(address, CurrentCharPtr);
+ } else {
+ num = code_int(num, pWrkrData);
+ num2ipv4(num, CurrentCharPtr);
+ strcpy(address, CurrentCharPtr);
+ }
+finalize_it:
+ RETiRet;
+}
+
+
+static void
+process_IPv4 (char* address, wrkrInstanceData_t *pWrkrData)
+{
+ unsigned num;
+
+ if(pWrkrData->pData->ipv4.randConsis){
+ findip(address, pWrkrData);
+ }else {
+ num = ipv42num(address);
+ num = code_int(num, pWrkrData);
+ num2ipv4(num, address);
+ }
+}
+
+
+static void
+simpleAnon(wrkrInstanceData_t *const pWrkrData, uchar *const msg, int *const hasChanged, int iplen)
+{
+ int maxidx = iplen - 1;
+
+ int j = -1;
+ for(int i = (pWrkrData->pData->ipv4.bits / 8); i > 0; i--) {
+ j++;
+ while('0' <= msg[maxidx - j] && msg[maxidx - j] <= '9') {
+ if(msg[maxidx - j] != pWrkrData->pData->ipv4.replaceChar) {
+ msg[maxidx - j] = pWrkrData->pData->ipv4.replaceChar;
+ *hasChanged = 1;
+ }
+ j++;
+ }
+ }
+}
+
+
+static void
+anonipv4(wrkrInstanceData_t *pWrkrData, uchar **msg, int *pLenMsg, int *idx, int *hasChanged)
+{
+ char address[16];
+ char caddress[16];
+ int offset = *idx;
+ uchar* msgcpy = *msg;
+ size_t iplen;
+ size_t caddresslen;
+ int oldLen = *pLenMsg;
+
+ if(syntax_ipv4((*msg) + offset, *pLenMsg - offset, &iplen)) {
+ if(pWrkrData->pData->ipv4.mode == SIMPLE) {
+ simpleAnon(pWrkrData, *msg + *idx, hasChanged, iplen);
+ *idx += iplen;
+ return;
+ }
+
+ assert(iplen < sizeof(address));
+ getip(*msg + offset, iplen, address);
+ offset += iplen;
+ strcpy(caddress, address);
+ process_IPv4(caddress, pWrkrData);
+ caddresslen = strlen(caddress);
+ *hasChanged = 1;
+
+ if(caddresslen != strlen(address)) {
+ *pLenMsg = *pLenMsg + ((int)caddresslen - (int)strlen(address));
+ *msg = (uchar*) malloc(*pLenMsg);
+ memcpy(*msg, msgcpy, *idx);
+ }
+ memcpy(*msg + *idx, caddress, caddresslen);
+ *idx = *idx + caddresslen;
+ if(*idx < *pLenMsg) {
+ memcpy(*msg + *idx, msgcpy + offset, oldLen - offset);
+ }
+ if(msgcpy != *msg) {
+ free(msgcpy);
+ }
+ }
+}
+
+
+static void
+code_ipv6_int(struct ipv6_int* ip, wrkrInstanceData_t *pWrkrData, int useEmbedded)
+{
+ unsigned long long randlow = 0;
+ unsigned long long randhigh = 0;
+ unsigned tmpRand;
+ int fullbits;
+
+ int bits = useEmbedded ? pWrkrData->pData->embeddedIPv4.bits : pWrkrData->pData->ipv6.bits;
+ enum mode anonmode = useEmbedded ? pWrkrData->pData->embeddedIPv4.anonmode : pWrkrData->pData->ipv6.anonmode;
+
+ if(bits == 128) { //has to be handled separately, since shift
+ //128 bits doesn't work on unsigned long long
+ ip->high = 0;
+ ip->low = 0;
+ } else if(bits > 64) {
+ ip->low = 0;
+ ip->high = (ip->high >> (bits - 64)) << (bits - 64);
+ } else if(bits == 64) {
+ ip->low = 0;
+ } else {
+ ip->low = (ip->low >> bits) << bits;
+ }
+ switch(anonmode) {
+ case ZERO:
+ break;
+ case RANDOMINT:
+ if(bits == 128) {
+ for(int i = 0; i < 8; i++) {
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*0xff);
+ ip->high <<= 8;
+ ip->high |= tmpRand;
+
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*0xff);
+ ip->low <<= 8;
+ ip->low |= tmpRand;
+ }
+ } else if(bits > 64) {
+ for(int i = 0; i < 8; i++) {
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*0xff);
+ ip->low <<= 8;
+ ip->low |= tmpRand;
+ }
+
+ bits -= 64;
+ fullbits = bits / 8;
+ bits = bits % 8;
+ while(fullbits > 0) {
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*0xff);
+ randhigh <<= 8;
+ randhigh |= tmpRand;
+ fullbits--;
+ }
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*((1 << bits) - 1));
+ randhigh <<= bits;
+ randhigh |= tmpRand;
+
+ ip->high |= randhigh;
+ } else if(bits == 64) {
+ for(int i = 0; i < 8; i++) {
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*0xff);
+ ip->low <<= 8;
+ ip->low |= tmpRand;
+ }
+ } else {
+ fullbits = bits / 8;
+ bits = bits % 8;
+ while(fullbits > 0) {
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*0xff);
+ randlow <<= 8;
+ randlow |= tmpRand;
+ fullbits--;
+ }
+ tmpRand = (unsigned)((rand_r(&(pWrkrData->randstatus))/(double)RAND_MAX)*((1 << bits) - 1));
+ randlow <<= bits;
+ randlow |= tmpRand;
+
+ ip->low |= randlow;
+ }
+ break;
+ case SIMPLE: //can't happen, since this case is caught at the start of anonipv4()
+ default:
+ LogError(0, RS_RET_INTERNAL_ERROR, "mmanon: unexpected code path reached in code_int function");
+ }
+}
+
+
+//separate function from recognising ipv6, since the recognition might get more
+//complex. This function always stays
+//the same, since it always gets an valid ipv6 input
+static void
+ipv62num(char* const address, const size_t iplen, struct ipv6_int* const ip)
+{
+ int num[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ int cyc = 0;
+ int dots = 0;
+ int val;
+ unsigned i;
+
+ for(i = 0; i < iplen && dots < 2; i++) {
+ val = getHexVal(address[i]);
+ if(val == -1) {
+ dots++;
+ if(dots < 2) {
+ cyc++;
+ }
+ } else {
+ num[cyc] = num[cyc] * 16 + val;
+ dots = 0;
+ }
+ }
+ if(dots == 2) {
+ if(i < iplen - 1) {
+ int shift = 0;
+ cyc = 7;
+ for(unsigned j = iplen - 1; j >= i; j--) {
+ val = getHexVal(address[j]);
+ if(val == -1) {
+ cyc--;
+ shift = 0;
+ } else {
+ val <<= shift;
+ shift += 4;
+ num[cyc] += val;
+ }
+ }
+ } else {
+ while(cyc < 8) {
+ num[cyc] = 0;
+ cyc++;
+ }
+ }
+ }
+
+ for(i = 0; i < 4; i++) {
+ ip->high <<= 16;
+ ip->high |= num[i];
+ }
+ while(i < 8) {
+ ip->low <<= 16;
+ ip->low |= num[i];
+ i++;
+ }
+}
+
+
+static void
+num2ipv6 (struct ipv6_int* ip, char* address)
+{
+ int num[8];
+ int i;
+
+ for(i = 7; i > 3; i--) {
+ num[i] = ip->low & 0xffff;
+ ip->low >>= 16;
+ }
+ while(i > -1) {
+ num[i] = ip->high & 0xffff;
+ ip->high >>= 16;
+ i--;
+ }
+
+ snprintf(address, 40, "%x:%x:%x:%x:%x:%x:%x:%x", num[0], num[1], num[2], num[3], num[4], num[5],
+ num[6], num[7]);
+}
+
+
+static int
+keys_equal_fn(void* key1, void* key2)
+{
+ struct ipv6_int *const k1 = (struct ipv6_int*) key1;
+ struct ipv6_int *const k2 = (struct ipv6_int*) key2;
+
+ return((k1->high == k2->high) && (k1->low == k2->low));
+}
+
+
+static unsigned
+hash_from_key_fn (void* k)
+{
+ struct ipv6_int *const key = (struct ipv6_int*) k;
+ unsigned hashVal;
+
+ hashVal = (key->high & 0xFFC00000) | (key->low & 0x3FFFFF);
+ return hashVal;
+}
+
+
+static void
+num2embedded (struct ipv6_int* ip, char* address)
+{
+ int num[8];
+ int i;
+
+ for(i = 7; i > 3; i--) {
+ num[i] = ip->low & 0xffff;
+ ip->low >>= 16;
+ }
+ while(i > -1) {
+ num[i] = ip->high & 0xffff;
+ ip->high >>= 16;
+ i--;
+ }
+
+ snprintf(address, 46, "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d", num[0], num[1], num[2], num[3], num[4], num[5],
+ (num[6] & 0xff00) >> 8, num[6] & 0xff, (num[7] & 0xff00) >> 8, num[7] & 0xff);
+}
+
+
+static rsRetVal
+findIPv6(struct ipv6_int* num, char* address, wrkrInstanceData_t *const pWrkrData, int useEmbedded)
+{
+ struct ipv6_int* hashKey = NULL;
+ DEFiRet;
+ struct hashtable* hash = useEmbedded? pWrkrData->pData->embeddedIPv4.hash : pWrkrData->pData->ipv6.hash;
+
+
+ if(hash == NULL) {
+ CHKmalloc(hash = create_hashtable(512, hash_from_key_fn, keys_equal_fn, NULL));
+ if(useEmbedded) {
+ pWrkrData->pData->embeddedIPv4.hash = hash;
+ } else {
+ pWrkrData->pData->ipv6.hash = hash;
+ }
+ }
+
+ char* val = (char*)(hashtable_search(hash, num));
+
+ if(val != NULL) {
+ strcpy(address, val);
+ } else {
+ CHKmalloc(hashKey = (struct ipv6_int*) malloc(sizeof(struct ipv6_int)));
+ hashKey->low = num->low;
+ hashKey->high = num->high;
+
+ if(useEmbedded) {
+ code_ipv6_int(num, pWrkrData, 1);
+ num2embedded(num, address);
+ } else {
+ code_ipv6_int(num, pWrkrData, 0);
+ num2ipv6(num, address);
+ }
+ char* hashString;
+ CHKmalloc(hashString = strdup(address));
+
+ if(!hashtable_insert(hash, hashKey, hashString)) {
+ DBGPRINTF("hashtable error: insert to %s-table failed",
+ useEmbedded ? "embedded ipv4" : "ipv6");
+ free(hashString);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ hashKey = NULL;
+ }
+finalize_it:
+ free(hashKey);
+ RETiRet;
+}
+
+
+static void
+process_IPv6 (char* address, wrkrInstanceData_t *pWrkrData, const size_t iplen)
+{
+ struct ipv6_int num = {0, 0};
+
+ ipv62num(address, iplen, &num);
+
+ if(pWrkrData->pData->ipv6.randConsis) {
+ findIPv6(&num, address, pWrkrData, 0);
+ } else {
+ code_ipv6_int(&num, pWrkrData, 0);
+ num2ipv6(&num, address);
+ }
+}
+
+
+static void
+anonipv6(wrkrInstanceData_t *pWrkrData, uchar **msg, int *pLenMsg, int *idx, int *hasChanged)
+{
+ size_t iplen = 0;
+ int offset = *idx;
+ char address[40];
+ uchar* msgcpy = *msg;
+ size_t caddresslen;
+ size_t oldLen = *pLenMsg;
+
+ int syn = syntax_ipv6(*msg + offset, *pLenMsg - offset, &iplen);
+ if(syn) {
+ assert(iplen < sizeof(address)); //has to be < instead of <= since address includes space for a '\0'
+ getip(*msg + offset, iplen, address);
+ offset += iplen;
+ process_IPv6(address, pWrkrData, iplen);
+
+ caddresslen = strlen(address);
+ *hasChanged = 1;
+
+ if(caddresslen != iplen) {
+ *pLenMsg = *pLenMsg + ((int)caddresslen - (int)iplen);
+ *msg = (uchar*) malloc(*pLenMsg);
+ memcpy(*msg, msgcpy, *idx);
+ }
+ memcpy(*msg + *idx, address, caddresslen);
+ *idx = *idx + caddresslen;
+ if(*idx < *pLenMsg) {
+ memcpy(*msg + *idx, msgcpy + offset, oldLen - offset);
+ }
+ if(msgcpy != *msg) {
+ free(msgcpy);
+ }
+ }
+}
+
+
+static size_t
+findV4Start(const uchar *const __restrict__ buf, size_t dotPos)
+{
+ while(dotPos > 0) {
+ if(buf[dotPos] == ':') {
+ return dotPos + 1;
+ }
+ dotPos--;
+ }
+ return -1; //should not happen
+}
+
+
+static int
+syntax_embedded(const uchar *const __restrict__ buf,
+ const size_t buflen,
+ size_t *const __restrict__ nprocessed,
+ size_t * v4Start)
+{
+ int lastSep = 0;
+ sbool hadAbbrev = 0;
+ int ipParts = 0;
+ int numLen;
+ int isIP = 0;
+ size_t ipv4Len;
+
+ while(*nprocessed < buflen) {
+ numLen = isValidHexNum(buf + *nprocessed, buflen - *nprocessed, nprocessed, 1);
+ if(numLen > 0) { //found a valid num
+ if((ipParts == 6 && hadAbbrev) || ipParts > 6) { //is 6 since the first part of
+ //IPv4 will also result in a valid hexvalue
+ isIP = 0;
+ goto done;
+ }
+ if (ipParts == 0 && lastSep && !hadAbbrev) {
+ isIP = 0;
+ goto done;
+ }
+ lastSep = 0;
+ ipParts++;
+ } else if (numLen == -1) { //':'
+ if(lastSep) {
+ if(hadAbbrev) {
+ isIP = 0;
+ goto done;
+ } else {
+ hadAbbrev = 1;
+ }
+ }
+ lastSep = 1;
+ } else if (numLen == -2) { //'.'
+ if (lastSep || (ipParts == 0 && hadAbbrev) || (ipParts <= 6 && !hadAbbrev)) {
+ isIP = 0;
+ goto done;
+ }
+ *v4Start = findV4Start(buf, (*nprocessed) - 1);
+ if(syntax_ipv4(buf + (*v4Start), buflen, &ipv4Len)) {
+ *nprocessed += (ipv4Len - ((*nprocessed) - (*v4Start)));
+ isIP = 1;
+ goto done;
+ } else {
+ isIP = 0;
+ goto done;
+ }
+ } else { //no valid num
+ isIP = 0;
+ goto done;
+ }
+ }
+
+ isIP = 0;
+
+done:
+ return isIP;
+}
+
+
+static void
+embedded2num(char* address, size_t v4Start, struct ipv6_int* ip)
+{
+ int num[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+ int cyc = 0;
+ int dots = 0;
+ int val;
+ unsigned i;
+
+ unsigned v4Val = ipv42num(address + v4Start);
+ num[7] = v4Val & 0xffff;
+ num[6] = (v4Val & 0xffff0000) >> 16;
+
+ for(i = 0; i < v4Start && dots < 2; i++) {
+ val = getHexVal(address[i]);
+ if(val == -1) {
+ dots++;
+ if(dots < 2) {
+ cyc++;
+ }
+ } else {
+ num[cyc] = num[cyc] * 16 + val;
+ dots = 0;
+ }
+ }
+ if(dots == 2) {
+ if(i < v4Start) {
+ int shift = 0;
+ cyc = 5;
+ for(unsigned j = v4Start - 1; j >= i; j--) {
+ val = getHexVal(address[j]);
+ if(val == -1) {
+ cyc--;
+ shift = 0;
+ } else {
+ val <<= shift;
+ shift += 4;
+ num[cyc] += val;
+ }
+ }
+ } else {
+ while(cyc < 6) {
+ num[cyc] = 0;
+ cyc++;
+ }
+ }
+ }
+
+ for(i = 0; i < 4; i++) {
+ ip->high <<= 16;
+ ip->high |= num[i];
+ }
+ while(i < 8) {
+ ip->low <<= 16;
+ ip->low |= num[i];
+ i++;
+ }
+}
+
+
+static void
+process_embedded (char* address, wrkrInstanceData_t *pWrkrData, size_t v4Start)
+{
+ struct ipv6_int num = {0, 0};
+
+ embedded2num(address, v4Start, &num);
+
+ if(pWrkrData->pData->embeddedIPv4.randConsis) {
+ findIPv6(&num, address, pWrkrData, 1);
+ } else {
+ code_ipv6_int(&num, pWrkrData, 1);
+ num2embedded(&num, address);
+ }
+}
+
+
+static void
+anonEmbedded(wrkrInstanceData_t *pWrkrData, uchar **msg, int *pLenMsg, int *idx, int *hasChanged)
+{
+ size_t iplen = 0;
+ int offset = *idx;
+ char address[46];
+ uchar* msgcpy = *msg;
+ unsigned caddresslen;
+ size_t oldLen = *pLenMsg;
+ size_t v4Start;
+
+ int syn = syntax_embedded(*msg + offset, *pLenMsg - offset, &iplen, &v4Start);
+ if(syn) {
+ assert(iplen < sizeof(address));
+ getip(*msg + offset, iplen, address);
+ offset += iplen;
+ process_embedded(address, pWrkrData, v4Start);
+
+ caddresslen = strlen(address);
+ *hasChanged = 1;
+
+ if(caddresslen != iplen) {
+ *pLenMsg = *pLenMsg + ((int)caddresslen - (int)iplen);
+ *msg = (uchar*) malloc(*pLenMsg);
+ memcpy(*msg, msgcpy, *idx);
+ }
+ memcpy(*msg + *idx, address, caddresslen);
+ *idx = *idx + caddresslen;
+ if(*idx < *pLenMsg) {
+ memcpy(*msg + *idx, msgcpy + offset, oldLen - offset);
+ }
+ if(msgcpy != *msg) {
+ free(msgcpy);
+ }
+ }
+}
+
+BEGINdoAction_NoStrings
+ smsg_t **ppMsg = (smsg_t **) pMsgData;
+ smsg_t *pMsg = ppMsg[0];
+ uchar *msg;
+ int lenMsg;
+ int i;
+ int hasChanged = 0;
+CODESTARTdoAction
+ lenMsg = getMSGLen(pMsg);
+ msg = (uchar*)strdup((char*)getMSG(pMsg));
+
+ for(i = 0 ; i <= lenMsg - 2 ; i++) {
+ if(pWrkrData->pData->embeddedIPv4.enable) {
+ anonEmbedded(pWrkrData, &msg, &lenMsg, &i, &hasChanged);
+ }
+ if(pWrkrData->pData->ipv4.enable) {
+ anonipv4(pWrkrData, &msg, &lenMsg, &i, &hasChanged);
+ }
+ if(pWrkrData->pData->ipv6.enable) {
+ anonipv6(pWrkrData, &msg, &lenMsg, &i, &hasChanged);
+ }
+ }
+ if(hasChanged) {
+ MsgReplaceMSG(pMsg, msg, lenMsg);
+ }
+ free(msg);
+ENDdoAction
+
+
+NO_LEGACY_CONF_parseSelectorAct
+
+
+BEGINmodExit
+CODESTARTmodExit
+ENDmodExit
+
+
+BEGINqueryEtryPt
+CODESTARTqueryEtryPt
+CODEqueryEtryPt_STD_OMOD_QUERIES
+CODEqueryEtryPt_STD_OMOD8_QUERIES
+CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES
+CODEqueryEtryPt_STD_CONF2_QUERIES
+ENDqueryEtryPt
+
+
+
+BEGINmodInit()
+CODESTARTmodInit
+ *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
+CODEmodInit_QueryRegCFSLineHdlr
+ DBGPRINTF("mmanon: module compiled with rsyslog version %s.\n", VERSION);
+ENDmodInit