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)