summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/mmanon.html34
-rw-r--r--plugins/mmanon/mmanon.c94
-rw-r--r--runtime/rsyslog.h2
3 files changed, 107 insertions, 23 deletions
diff --git a/doc/mmanon.html b/doc/mmanon.html
index b8691247..af462d2e 100644
--- a/doc/mmanon.html
+++ b/doc/mmanon.html
@@ -23,9 +23,23 @@ such exists.
<p>&nbsp;</p>
<p><b>Action Confguration Parameters</b>:</p>
<ul>
-<li><b>replacementChar</b><br>In simple mode, this sets the character
+<li><b>ipv4.bits</b> - default 16<br>
+This set the number of bits that should be anonymized (bits are from the
+right, so lower bits are anonymized first). This setting permits to save
+network information while still anonymizing user-specific data. The more
+bits you discard, the better the anonymization obviously is. The default
+of 16 bits reflects what German data privacy rules consider as being
+sufficinetly anonymized. We assume, this can also be used as a rough
+but conservative guideline for other countries.<br>
+Note: when in simple mode, only bits on a byte boundary can be specified.
+As such, any value other than 8, 16, 24 or 32 is invalid. If an invalid
+value is given, it is rounded to the next byte boundary (so we favor stronger
+encyrption in that case). For example, a bit value of 12 will become 16 in
+simple mode (an error message is also emitted).
+<li><b>replacementChar</b> - default "x"<br>
+In simple mode, this sets the character
that the to-be-anonymized part of the IP address is to be overwritten
-with. The default is "x".
+with.
</ul>
<p><b>Caveats/Known Bugs:</b>
@@ -37,10 +51,9 @@ and it got limited practice drill so far.
<li>The anonymization replaces the numerical parts of the ip address.
However, the number of digits is not normalized. So one can probably
draw conlusions just based on the length of the various octets.
-<li>Needed config parameters are missing.
</ul>
-<p><b>Sample:</b></p>
+<p><b>Samples:</b></p>
<p>In this snippet, we write one file without anonymization and another one
with the message anonymized. Note that once mmanon has run, access to the
original message is no longer possible (execept if stored in user
@@ -51,6 +64,19 @@ action(type="mmanon")
action(type="omfile" file="/path/to/anon.log")
</textarea>
+<p>This next snippet is almost identical to the first one, but
+here we anonymize the full IPv4 address. Note that by
+modifying the number of bits, you can anonymize different parts
+of the address. Keep in mind that in simple mode, the bit values
+must match IP address bytes, so for IPv4 only the values 8, 16, 24 and
+32 are valid. Also, in this example the replacement is done
+via zeros instead of lower-case "x"-letters.
+<p><textarea rows="5" cols="60">module(load="mmanon")
+action(type="omfile" file="/path/to/non-anon.log")
+action(type="mmanon" ipv4.bits="32" replacementChar="0")
+action(type="omfile" file="/path/to/anon.log")
+</textarea>
+
<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>] [<a href="manual.html">manual
index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
diff --git a/plugins/mmanon/mmanon.c b/plugins/mmanon/mmanon.c
index f84cc8e9..c9add1a1 100644
--- a/plugins/mmanon/mmanon.c
+++ b/plugins/mmanon/mmanon.c
@@ -49,6 +49,11 @@ DEF_OMOD_STATIC_DATA
typedef struct _instanceData {
char replChar;
+ int8_t mode;
+# define SIMPLE_MODE 0 /* just overwrite */
+ struct {
+ int8_t bits;
+ } ipv4;
} instanceData;
struct modConfData_s {
@@ -61,7 +66,9 @@ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current ex
/* tables for interfacing with the v6 config system */
/* action (instance) parameters */
static struct cnfparamdescr actpdescr[] = {
+ { "mode", eCmdHdlrGetWord, 0 },
{ "replacementchar", eCmdHdlrGetChar, 0 },
+ { "ipv4.bits", eCmdHdlrInt, 0 },
};
static struct cnfparamblk actpblk =
{ CNFPARAMBLK_VERSION,
@@ -111,12 +118,15 @@ ENDfreeInstance
static inline void
setInstParamDefaults(instanceData *pData)
{
+ pData->mode = SIMPLE_MODE;
pData->replChar = 'x';
+ pData->ipv4.bits = 16;
}
BEGINnewActInst
struct cnfparamvals *pvals;
int i;
+ sbool bHadBitsErr;
CODESTARTnewActInst
DBGPRINTF("newActInst (mmanon)\n");
if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) {
@@ -131,17 +141,50 @@ CODESTARTnewActInst
for(i = 0 ; i < actpblk.nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
- if(!strcmp(actpblk.descr[i].name, "replacementchar")) {
+ if(!strcmp(actpblk.descr[i].name, "mode")) {
+ if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"simple",
+ sizeof("simple")-1)) {
+ pData->mode = SIMPLE_MODE;
+ } else {
+ char *cstr = es_str2cstr(pvals[i].val.d.estr, NULL);
+ errmsg.LogError(0, RS_RET_INVLD_MODE,
+ "mmanon: invalid anonymization mode '%s' - ignored",
+ cstr);
+ free(cstr);
+ }
pData->replChar = es_getBufAddr(pvals[i].val.d.estr)[0];
- //pData->replChar = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
- //} else if(!strcmp(actpblk.descr[i].name, "serverport")) {
- // pData->port = (int) pvals[i].val.d.n;
+ } else if(!strcmp(actpblk.descr[i].name, "replacementchar")) {
+ pData->replChar = es_getBufAddr(pvals[i].val.d.estr)[0];
+ } else if(!strcmp(actpblk.descr[i].name, "ipv4.bits")) {
+ pData->ipv4.bits = (int8_t) pvals[i].val.d.n;
} else {
dbgprintf("mmanon: program error, non-handled "
"param '%s'\n", actpblk.descr[i].name);
}
}
+ if(pData->mode == SIMPLE_MODE) {
+ bHadBitsErr = 0;
+ if(pData->ipv4.bits < 8) {
+ pData->ipv4.bits = 8;
+ bHadBitsErr = 1;
+ } else if(pData->ipv4.bits < 16) {
+ pData->ipv4.bits = 16;
+ bHadBitsErr = 1;
+ } else if(pData->ipv4.bits < 24) {
+ pData->ipv4.bits = 24;
+ bHadBitsErr = 1;
+ } else if(pData->ipv4.bits != 32) {
+ pData->ipv4.bits = 32;
+ bHadBitsErr = 1;
+ }
+ if(bHadBitsErr)
+ errmsg.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
@@ -180,8 +223,9 @@ void
anonip(instanceData *pData, uchar *msg, int lenMsg, int *idx)
{
int i = *idx;
- int octet;
- int ipstart;
+ int octet[4];
+ int ipstart[4];
+ int j;
dbgprintf("DDDD: in anonip: %s\n", msg+(*idx));
while(i < lenMsg && (msg[i] <= '0' || msg[i] >= '9')) {
@@ -191,24 +235,36 @@ dbgprintf("DDDD: in anonip: %s\n", msg+(*idx));
goto done;
/* got digit, let's see if ip */
- ipstart = i;
- octet = getnum(msg, lenMsg, &i);
- if(octet > 255 || msg[i] != '.') goto done;
+ ipstart[0] = i;
+ octet[0] = getnum(msg, lenMsg, &i);
+ if(octet[0] > 255 || msg[i] != '.') goto done;
++i;
- octet = getnum(msg, lenMsg, &i);
- if(octet > 255 || msg[i] != '.') goto done;
+ ipstart[1] = i;
+ octet[1] = getnum(msg, lenMsg, &i);
+ if(octet[1] > 255 || msg[i] != '.') goto done;
++i;
- octet = getnum(msg, lenMsg, &i);
- if(octet > 255 || msg[i] != '.') goto done;
+ ipstart[2] = i;
+ octet[2] = getnum(msg, lenMsg, &i);
+ if(octet[2] > 255 || msg[i] != '.') goto done;
++i;
- octet = getnum(msg, lenMsg, &i);
- if(octet > 255 || msg[i] != ' ') goto done;
+ ipstart[3] = i;
+ octet[3] = getnum(msg, lenMsg, &i);
+ if(octet[3] > 255 || !(msg[i] == ' ' || msg[i] == ':')) goto done;
/* OK, we now found an ip address */
- while(ipstart < i) {
- if(msg[ipstart] != '.')
- msg[ipstart] = pData->replChar;
- ++ipstart;
+ if(pData->ipv4.bits == 8)
+ j = ipstart[3];
+ else if(pData->ipv4.bits == 16)
+ j = ipstart[2];
+ else if(pData->ipv4.bits == 24)
+ j = ipstart[1];
+ else /* due to our checks, this *must* be 32 */
+ j = ipstart[0];
+dbgprintf("DDDD: ipstart is %d: %s\n", j, msg+j);
+ while(j < i) {
+ if(msg[j] != '.')
+ msg[j] = pData->replChar;
+ ++j;
}
done: *idx = i;
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 7e3761e0..8dad09a4 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -399,6 +399,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_DS_PROP_SEQ_ERR = -2308,/**< property sequence error deserializing object */
RS_RET_TPL_INVLD_PROP = -2309,/**< property name error in template (unknown name) */
RS_RET_NO_RULEBASE = -2310,/**< mmnormalize: rulebase can not be found or otherwise invalid */
+ RS_RET_INVLD_MODE = -2311,/**< invalid mode specified in configuration */
+ RS_RET_INVLD_ANON_BITS = -2312,/**< mmanon: invalid number of bits to anonymize specified */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */