Package: sysklogd
Version: 1.4.1-10

I have just needed to do some log relaying across multiple hops and I found that the generic sysklogd shipped with my linux systems (debian woody and sarge) didn't handle this properly (each hop set the source to be the machine before it, so the final logs showed the sources to be the relay boxes in the middle. I examined several alturnatives for this task and ended up deciding not to use them (for various reasons that I can go into if someone is interested). Instead I developed the attached patch against sysklogd-1.4.1 that does the following.

1. when sending messages over the network put in a timestamp and source

2. when receiving a message from anything other then the local machine examine the message and after it's validated that the timestamp could be valid then check to see if the next block could be a hostname (alphanumeric, '.', '-'), if so use that as the source rather then the previous hop.

3. when printing message repeated x times, append the message that was repeated so that when logs from that machine are interleaved with other machines you don't have to hunt back through the combined logs to find out WHICH message was repeated x times.

I have sent this to the sysklog maintainer, but am sending it to you as well as the debian sysklog maintainer. one hunk of the patch needs to be applied manually against the -17 patches

in an ideal world there would be a switch to enable/disable the hostname parseing since it can fail, it would also be useful to have a switch that always prepended the source to the message (so that a message that goes through multiple hops would show the path it followed), but I don't need those so I'm not going to work on that right now.

David Lang

diff -u sysklogd-1.4.1.orig/syslogd.c sysklogd-1.4.1/syslogd.c
--- sysklogd-1.4.1.orig/syslogd.c       2001-03-11 11:40:10.000000000 -0800
+++ sysklogd-1.4.1/syslogd.c    2006-04-28 11:59:01.000000000 -0700
@@ -1539,6 +1539,7 @@
        int fac, prilev, lognum;
        int msglen;
        char *timestamp;
+       char *q, c;

        dprintf("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, 
from, msg);

@@ -1561,6 +1562,38 @@
                timestamp = msg;
                msg += 16;
                msglen -= 16;
+ /* + * If there is a timestamp then we want to look for a hostname
+                * since messages from the local machine don't have names only
+                * look in the message for the name if it's not from localhost
+                *
+                * use the first word as the from name, but only if it could be
+ * a valid hostname (AIX sends some syslog messages with a + * timestamp, but no hostname. without the character set logic
+                * we would end up with application names in the hostname field
+                */
+               if ( strcmp(from, LocalHostName) ) {
+                       q = msg;
+                       while ((c = *q++) && q < msg + msglen) {
+                               if (c == ' ') {
+                                       q--;
+                                       msglen -= q - msg + 1;
+ from = msg; + *q++ = '\0'; + msg = q;
+                                       q += msglen;
+                               } else if ( !( (c >= '0' && c <= '9') || \
+                                   (c >= 'A' && c <= 'Z') || \
+                                   (c >= 'a' && c <= 'z') || \
+                                   c == '.' || c == '-' ) ) {
+                                       /* this isn't a valid hostname
+                                        * (alphanumberic, '.', '-') so
+                                        * use the one from the network instead
+                                        */
+                                       q += msglen;
+                               }
+                       }
+               }
        }

        /* extract facility and priority level */
@@ -1688,8 +1721,8 @@
                v->iov_base = msg;
                v->iov_len = strlen(msg);
        } else if (f->f_prevcount > 1) {
-               (void) snprintf(repbuf, sizeof(repbuf), "last message repeated %d 
times",
-                   f->f_prevcount);
+               (void) snprintf(repbuf, sizeof(repbuf), "last message repeated %d 
times %s",
+                   f->f_prevcount,f->f_prevline);
                v->iov_base = repbuf;
                v->iov_len = strlen(repbuf);
        } else {
@@ -1771,7 +1804,12 @@
                        dprintf("Not sending message to remote.\n");
                else {
                        f->f_time = now;
-                       (void) snprintf(line, sizeof(line), "<%d>%s\n", 
f->f_prevpri, \
+                       /*
+                        * when sending over the network add the source and 
timestamp.
+                        */
+                       (void) snprintf(line, sizeof(line), "<%d>%s %s %s\n", 
f->f_prevpri, \
+                               (char *) iov[0].iov_base, \
+                               from, \
                                (char *) iov[4].iov_base);
                        l = strlen(line);
                        if (l > MAXLINE)
diff -u sysklogd-1.4.1.orig/syslogd.c sysklogd-1.4.1/syslogd.c
--- sysklogd-1.4.1.orig/syslogd.c       2001-03-11 11:40:10.000000000 -0800
+++ sysklogd-1.4.1/syslogd.c    2006-04-28 11:59:01.000000000 -0700
@@ -1539,6 +1539,7 @@
        int fac, prilev, lognum;
        int msglen;
        char *timestamp;
+       char *q, c;
 
        dprintf("logmsg: %s, flags %x, from %s, msg %s\n", textpri(pri), flags, 
from, msg);
 
@@ -1561,6 +1562,38 @@
                timestamp = msg;
                msg += 16;
                msglen -= 16;
+               /* 
+                * If there is a timestamp then we want to look for a hostname
+                * since messages from the local machine don't have names only
+                * look in the message for the name if it's not from localhost
+                *
+                * use the first word as the from name, but only if it could be
+                * a valid hostname (AIX sends some syslog messages with a 
+                * timestamp, but no hostname. without the character set logic
+                * we would end up with application names in the hostname field
+                */
+               if ( strcmp(from, LocalHostName) ) {
+                       q = msg;
+                       while ((c = *q++) && q < msg + msglen) {
+                               if (c == ' ') {
+                                       q--;
+                                       msglen -= q - msg + 1;
+                                       from = msg; 
+                                       *q++ = '\0'; 
+                                       msg = q;
+                                       q += msglen;
+                               } else if ( !( (c >= '0' && c <= '9') || \
+                                   (c >= 'A' && c <= 'Z') || \
+                                   (c >= 'a' && c <= 'z') || \
+                                   c == '.' || c == '-' ) ) {
+                                       /* this isn't a valid hostname
+                                        * (alphanumberic, '.', '-') so
+                                        * use the one from the network instead
+                                        */
+                                       q += msglen;
+                               }
+                       }
+               }
        }
 
        /* extract facility and priority level */
@@ -1688,8 +1721,8 @@
                v->iov_base = msg;
                v->iov_len = strlen(msg);
        } else if (f->f_prevcount > 1) {
-               (void) snprintf(repbuf, sizeof(repbuf), "last message repeated 
%d times",
-                   f->f_prevcount);
+               (void) snprintf(repbuf, sizeof(repbuf), "last message repeated 
%d times %s",
+                   f->f_prevcount,f->f_prevline);
                v->iov_base = repbuf;
                v->iov_len = strlen(repbuf);
        } else {
@@ -1771,7 +1804,12 @@
                        dprintf("Not sending message to remote.\n");
                else {
                        f->f_time = now;
-                       (void) snprintf(line, sizeof(line), "<%d>%s\n", 
f->f_prevpri, \
+                       /*
+                        * when sending over the network add the source and 
timestamp.
+                        */
+                       (void) snprintf(line, sizeof(line), "<%d>%s %s %s\n", 
f->f_prevpri, \
+                               (char *) iov[0].iov_base, \
+                               from, \
                                (char *) iov[4].iov_base);
                        l = strlen(line);
                        if (l > MAXLINE)

Reply via email to