Rainer Gerhards b326c76f45 style: normalize C source formatting via clang-format (PoC)
This commit applies the new canonical formatting style using `clang-format` with custom settings (notably 4-space indentation), as part of our shift toward automated formatting normalization.

⚠️ No functional changes are included — only whitespace and layout modifications as produced by `clang-format`.

This change is part of the formatting modernization strategy discussed in:
https://github.com/rsyslog/rsyslog/issues/5747

Key context:
- Formatting is now treated as a disposable view, normalized via tooling.
- The `.clang-format` file defines the canonical style.
- A fixup script (`devtools/format-code.sh`) handles remaining edge cases.
- Formatting commits are added to `.git-blame-ignore-revs` to reduce noise.
- Developers remain free to format code however they prefer locally.
2025-07-16 13:56:21 +02:00

1309 lines
38 KiB
C

/* 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;
default:
// No action needed for other cases
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