Project

General

Profile

[WAD] How to exclude particular SSL errors from error.log?

Added by cadence about 1 year ago

Hi. I noticed that 90% of the log entries in my error.log file are the two following lines:

(mod_openssl.c.3247) SSL: 1 error:0A000102:SSL routines::unsupported protocol
(mod_openssl.c.3247) SSL: 1 error:0A00018C:SSL routines::version too low

Is there any way to filter them out?

I would expect these to be part of the debug.log-ssl-noise option, but they are not. Are there any tricks (or proper solutions) to prevent Lighttpd from logging these two lines? I'm on Lighttpd 1.4.63.

Thanks!


Replies (11)

RE: How to exclude particular SSL errors from error.log? - Added by gstrauss about 1 year ago

Is there any way to filter them out?

As mentioned in a prior post: use a piped logger and filter as you please.

If you have configured your system to accept only TLSv1.3 and you are seeing many unsupported protocol or version too low errors, then a competent admin might want to see this in his or her error logs to be able to gauge how frequently clients failed to connect due to the higher protocol setting.

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by cadence about 1 year ago

Right, but in that previous post, we were able to come up with that $HTTP["request-method"] != "" trick. Is there something similar for these SSL error messages? I would like to avoid the piped logger method, if possible.

I have already investigated the sources of these messages using tshark . These are mostly outdated IoT devices and routers, as well as possible attacks that send malformed SSL requests. There is not much I can do about them, so I would like to silence them.
Currently, I block most of the main offenders on my firewall, but many devices just ping my server occasionally, so blocking them on the firewall is not very efficient.

I use these commands to collect the offending IP addresses:
tshark -T fields -e ip.dst -e _ws.col.Info port 443 2>/dev/null |grep "Protocol Version"
tshark -T fields -e ip.src -e _ws.col.Info port 443 2>/dev/null |grep "Alert (Level:"

So, given all the above, it would be great if I could just configure Lighttpd to drop these.

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by gstrauss about 1 year ago

debug.log-ssl-noise hides TLS "errors" that may not indicate a real error, and might be part of normal operation or improper client disconnects.

unsupported protocol and version too low are real errors. That is why I marked this forum post as Works As Designed (WAD).

I have no plans to make any change you have recommended to the error logs.

How to exclude particular SSL errors from error.log?

Use a filter. Your squeamish response to this bonafide solution hints at your skill levels in this area, and subsequently how much credence I grant to your opinions and suggestions. Your log rotation and retention policy should handle log files of the sizes that you are seeing.

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by gstrauss about 1 year ago

Also note that the $HTTP["request-method"] != "" trick will stop working in lighttpd 1.4.72 when you will instead be able to $HTTP["request-method"] == "PRI"

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by cadence about 1 year ago

debug.log-ssl-noise hides TLS "errors" that may not indicate a real error, and might be part of normal operation or improper client disconnects.
unsupported protocol and version too low are real errors. That is why I marked this forum post as Works As Designed (WAD).

Okay, this makes sense to me.

Use a filter.

I'll play around with it next week. I will share my results here if I can come up with something that uses minimum CPU and RAM.

Thanks. Great software overall, I have been using it since 2016 and love it!

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by gstrauss about 1 year ago

If you're storing logs to a file (rather than to a filter or to syslog), you might alternatively filter the log after the operational step of log rotation (i.e. if you have an automated process to rotate your logs). This can be a part of your log rotation and retention policy.

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by cadence about 1 year ago

I was able to make the piped logger method work. It takes less than 3 MB of RAM and uses almost no CPU. For those who might find this post while trying to solve the same problem, here is the code I wrote:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char buffer[1024];
    FILE* fp;

    fp = fopen("/var/log/lighttpd/error.log", "a");
    if (fp == NULL) {
        fprintf(stderr, "Failed to open file\n");
        return EXIT_FAILURE;
    }

    while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        if (    strstr(buffer, "SSL routines::unsupported protocol") == NULL
             && strstr(buffer, "SSL routines::version too low") == NULL
           )
        {
            fputs(buffer, fp);
            fflush(fp);  // Flush the file buffer
        }
    }

    fclose(fp);

    return EXIT_SUCCESS;
}

You need to compile it:

gcc -O3 log_filter_for_lighttpd.c

And then copy it somewhere where Lighttpd can access it, with the right permissions to the file, e.g.:

sudo cp a.out /bin/log_filter_for_lighttpd
sudo chown root.root /bin/log_filter_for_lighttpd
sudo chmod 755 /bin/log_filter_for_lighttpd

Then modify server.errorlog in your lighttpd.conf file to point to this new binary:
server.errorlog = "|/bin/log_filter_for_lighttpd"

Restart lighttpd. Using ps -afx command, you should see something like this:

363966 ?        Ss     0:06 /usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf
363969 ?        S      0:00  \_ /bin/sh -c /bin/log_filter_for_lighttpd
363971 ?        S      0:00  |   \_ /bin/log_filter_for_lighttpd

This can be extended to filter out different lines from the log files, or to output one line of error for every 100 occurrences of the error (to keep tabs on things and make sure the server is not being flooded with these requests from clients), etc.

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by cadence about 1 year ago

Actually, it only uses 1 MB of RAM (I was looking at the wrong number).

For completeness, here is the actual code I use on my server, which prints the noisy errors only once for every 100 occurrences:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char buffer[1024];
    FILE* fp;
    int counter_protocol = 0;
    int counter_version = 0;
    char* count_message = " (this error occurred 100 times since it was last logged)\n";

    fp = fopen("/var/log/lighttpd/error.log", "a");
    if (fp == NULL) {
        fprintf(stderr, "Failed to open file\n");
        return EXIT_FAILURE;
    }

    while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        char* newline = strchr(buffer, '\n');
        if (newline) *newline = '\0';

        if (strstr(buffer, "SSL routines::unsupported protocol") != NULL) {
            counter_protocol++;
            if (counter_protocol >= 100) {
                fputs(buffer, fp);
                fputs(count_message, fp);
                fflush(fp);
                counter_protocol = 0;
            }
        } else if (strstr(buffer, "SSL routines::version too low") != NULL) {
            counter_version++;
            if (counter_version >= 100) {
                fputs(buffer, fp);
                fputs(count_message, fp);
                fflush(fp);
                counter_version = 0;
            }
        } else {
            fputs(buffer, fp);
            fputs("\n", fp); // Add back the newline for non-filtered lines
            fflush(fp);
        }
    }

    fclose(fp);

    return EXIT_SUCCESS;
}

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by cadence about 1 year ago

Argh, I just noticed that we also need to handle error.log rotation. This is why I always try to avoid writing my own code for things like that. There are always some edge cases that are easy to miss if you are not a developer of this kind of software.

Here is the updated version. I also added two more errors that were quite noisy on my server.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    char buffer[1024];
    FILE* fp = NULL;
    int counter_protocol = 0;
    int counter_version = 0;
    int counter_scriptname = 0;
    int counter_httprequest = 0;
    int line_counter = -1;
    char* count_message = " (this error occurred 100 times since it was last logged)\n";

    while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        char* newline = strchr(buffer, '\n');
        if (newline) *newline = '\0';

        if (++line_counter % 1000 == 0) { // Reopen the file every 1000 lines for logrotate
            if (fp != NULL) {
                fclose(fp);
            }
            fp = fopen("/var/log/lighttpd/error.log", "a");
            if (fp == NULL) {
                fprintf(stderr, "Failed to open file\n");
                return EXIT_FAILURE;
            }
        }

        if (strstr(buffer, "SSL routines::unsupported protocol") != NULL) {
            counter_protocol++;
            if (counter_protocol >= 100) {
                fputs(buffer, fp);
                fputs(count_message, fp);
                fflush(fp);
                counter_protocol = 0;
            }
        } else if (strstr(buffer, "SSL routines::version too low") != NULL) {
            counter_version++;
            if (counter_version >= 100) {
                fputs(buffer, fp);
                fputs(count_message, fp);
                fflush(fp);
                counter_version = 0;
            }
        } else if (strstr(buffer, "FastCGI-stderr:WARNING: SCRIPT_NAME does not match REQUEST_URI") != NULL) {
            counter_scriptname++;
            if (counter_scriptname >= 100) {
                fputs(buffer, fp);
                fputs(count_message, fp);
                fflush(fp);
                counter_scriptname = 0;
            }
        } else if (strstr(buffer, "SSL routines::http request") != NULL) {
            counter_httprequest++;
            if (counter_httprequest >= 100) {
                fputs(buffer, fp);
                fputs(count_message, fp);
                fflush(fp);
                counter_httprequest = 0;
            }
        } else {
            fputs(buffer, fp);
            fputs("\n", fp); 
            fflush(fp);
        }
    }

    if (fp != NULL) {
        fclose(fp);
    }

    return EXIT_SUCCESS;
}

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by gstrauss about 1 year ago

Thank you for sharing your code.

Since you can not guarantee when errors occur, reopening the log every 1000 lines may not occur predictably.

Here is some untested code -- it compiles -- which reopens the log whenever it receives SIGHUP. The code disables stdio buffering to avoid extra calls to fflush() and writes output to stdout, which has been redirected to the (hard-coded) log file. (This could be slightly more robust if instead of signal(), sigaction() were used to set SA_RESTART for SIGHUP to avoid potential partial reads or writes when SIGHUP is received.)

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void
reopen_log (int sig)
{
    (void)sig; /*(unused)*/
    if (NULL == freopen("/var/log/lighttpd/error.log", "a", stdout)) {
        perror("open()");
        exit(EXIT_FAILURE);
    }
    setvbuf(stdout, NULL, _IONBF, 0);
}

int
main (void)
{
    signal(SIGHUP, reopen_log);
    raise(SIGHUP);

    char buffer[4096];
    struct { const char *str; int count; } list[] = {
      { "SSL routines::unsupported protocol", 0 }
     ,{ "SSL routines::version too low", 0 }
     ,{ "SSL routines::http request", 0 }
    };

    while (fgets(buffer, sizeof(buffer), stdin)) {

        int i;
        for (i = 0; i < sizeof(list)/sizeof(*list); ++i) {
            if (strstr(buffer, list[i].str) != NULL)
                break;
        }

        if (i == sizeof(list)/sizeof(*list))
            fputs(buffer, stdout);
        else {
            ++list[i].count;
            if (__builtin_expect( (list[i].count >= 100), 0)) {
                list[i].count = 0;
                size_t len = strlen(buffer);
                /*assert(len);*//*(must be > 0 to match non-zero list str)*/
                if (buffer[len-1] == '\n')
                    --len;
                printf("%.*s (occurred 100 times since last logged)\n",
                       (int)len, buffer);
            }
        }
    }

    return EXIT_SUCCESS;
}

RE: [WAD] How to exclude particular SSL errors from error.log? - Added by cadence about 1 year ago

Nice, I like it! It's a better approach than mine. I'll test it in my environment later this week and report back if I notice any issues.

Thanks, I appreciate it!

    (1-11/11)