When parsing remote messages, require them to have standard timestamp

field, and support properly parse out the hostname as described by RFC3164,
which wasn't done before.  However, don't discard message if it doesn't
have hostname, for compatibility.

Enable logging of the message supplied hostname instead of real hostname
with -H switch.

PR:		200933
Reported by:	Konstantin Pavlov <thresh nginx.com>
MFC after:	2 months
This commit is contained in:
Gleb Smirnoff 2017-12-05 19:54:55 +00:00
parent 08f16d0c01
commit 50387adce2
2 changed files with 105 additions and 62 deletions

View File

@ -28,7 +28,7 @@
.\" @(#)syslogd.8 8.1 (Berkeley) 6/6/93 .\" @(#)syslogd.8 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd March 3, 2017 .Dd November 28, 2017
.Dt SYSLOGD 8 .Dt SYSLOGD 8
.Os .Os
.Sh NAME .Sh NAME
@ -36,7 +36,7 @@
.Nd log systems messages .Nd log systems messages
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl 468ACcdFkNnosTuv .Op Fl 468ACcdFHkNnosTuv
.Op Fl a Ar allowed_peer .Op Fl a Ar allowed_peer
.Op Fl b Ar bind_address .Op Fl b Ar bind_address
.Op Fl f Ar config_file .Op Fl f Ar config_file
@ -229,6 +229,9 @@ and
to run to run
.Nm , .Nm ,
and wants to monitor when and how it exits. and wants to monitor when and how it exits.
.It Fl H
When logging remote messages use hostname from the message (if supplied)
instead of using address from which the message was received.
.It Fl k .It Fl k
Disable the translation of Disable the translation of
messages received with facility messages received with facility

View File

@ -173,7 +173,6 @@ static STAILQ_HEAD(, socklist) shead = STAILQ_HEAD_INITIALIZER(shead);
#define IGN_CONS 0x001 /* don't print on console */ #define IGN_CONS 0x001 /* don't print on console */
#define SYNC_FILE 0x002 /* do fsync on file after printing */ #define SYNC_FILE 0x002 /* do fsync on file after printing */
#define ADDDATE 0x004 /* add a date to the message */
#define MARK 0x008 /* this message is a mark */ #define MARK 0x008 /* this message is a mark */
#define ISKERNEL 0x010 /* kernel generated message */ #define ISKERNEL 0x010 /* kernel generated message */
@ -324,6 +323,7 @@ static int logflags = O_WRONLY|O_APPEND; /* flags used to open log files */
static char bootfile[MAXLINE+1]; /* booted kernel file */ static char bootfile[MAXLINE+1]; /* booted kernel file */
static int RemoteAddDate; /* Always set the date on remote messages */ static int RemoteAddDate; /* Always set the date on remote messages */
static int RemoteHostname; /* Log remote hostname from the message */
static int UniquePriority; /* Only log specified priority? */ static int UniquePriority; /* Only log specified priority? */
static int LogFacPri; /* Put facility and priority in log message: */ static int LogFacPri; /* Put facility and priority in log message: */
@ -352,7 +352,7 @@ static void domark(int);
static void fprintlog(struct filed *, int, const char *); static void fprintlog(struct filed *, int, const char *);
static void init(int); static void init(int);
static void logerror(const char *); static void logerror(const char *);
static void logmsg(int, const char *, const char *, int); static void logmsg(int, const char *, const char *, const char *, int);
static void log_deadchild(pid_t, int, const char *); static void log_deadchild(pid_t, int, const char *);
static void markit(void); static void markit(void);
static int socksetup(struct peer *); static int socksetup(struct peer *);
@ -361,7 +361,7 @@ static int socklist_recv_sock(struct socklist *);
static int socklist_recv_signal(struct socklist *); static int socklist_recv_signal(struct socklist *);
static void sighandler(int); static void sighandler(int);
static int skip_message(const char *, const char *, int); static int skip_message(const char *, const char *, int);
static void printline(const char *, char *, int); static void parsemsg(const char *, char *);
static void printsys(char *); static void printsys(char *);
static int p_open(const char *, pid_t *); static int p_open(const char *, pid_t *);
static void reapchild(int); static void reapchild(int);
@ -454,7 +454,7 @@ main(int argc, char *argv[])
if (madvise(NULL, 0, MADV_PROTECT) != 0) if (madvise(NULL, 0, MADV_PROTECT) != 0)
dprintf("madvise() failed: %s\n", strerror(errno)); dprintf("madvise() failed: %s\n", strerror(errno));
while ((ch = getopt(argc, argv, "468Aa:b:cCdf:Fkl:m:nNop:P:sS:Tuv")) while ((ch = getopt(argc, argv, "468Aa:b:cCdf:FHkl:m:nNop:P:sS:Tuv"))
!= -1) != -1)
switch (ch) { switch (ch) {
#ifdef INET #ifdef INET
@ -518,6 +518,9 @@ main(int argc, char *argv[])
case 'F': /* run in foreground instead of daemon */ case 'F': /* run in foreground instead of daemon */
Foreground++; Foreground++;
break; break;
case 'H':
RemoteHostname = 1;
break;
case 'k': /* keep remote kern fac */ case 'k': /* keep remote kern fac */
KeepKernFac = 1; KeepKernFac = 1;
break; break;
@ -772,7 +775,7 @@ socklist_recv_sock(struct socklist *sl)
socklen_t sslen; socklen_t sslen;
const char *hname; const char *hname;
char line[MAXLINE + 1]; char line[MAXLINE + 1];
int date, len; int len;
sslen = sizeof(ss); sslen = sizeof(ss);
len = recvfrom(sl->sl_socket, line, sizeof(line) - 1, 0, sa, &sslen); len = recvfrom(sl->sl_socket, line, sizeof(line) - 1, 0, sa, &sslen);
@ -786,19 +789,17 @@ socklist_recv_sock(struct socklist *sl)
} }
/* Received valid data. */ /* Received valid data. */
line[len] = '\0'; line[len] = '\0';
if (sl->sl_ss.ss_family == AF_LOCAL) { if (sl->sl_ss.ss_family == AF_LOCAL)
hname = LocalHostName; hname = LocalHostName;
date = 0; else {
} else {
hname = cvthname(sa); hname = cvthname(sa);
unmapped(sa); unmapped(sa);
if (validate(sa, hname) == 0) { if (validate(sa, hname) == 0) {
dprintf("Message from %s was ignored.", hname); dprintf("Message from %s was ignored.", hname);
return (-1); return (-1);
} }
date = RemoteAddDate ? ADDDATE : 0;
} }
printline(hname, line, date); parsemsg(hname, line);
return (0); return (0);
} }
@ -836,7 +837,7 @@ usage(void)
{ {
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
"usage: syslogd [-468ACcdFknosTuv] [-a allowed_peer]", "usage: syslogd [-468ACcdFHknosTuv] [-a allowed_peer]",
" [-b bind_address] [-f config_file]", " [-b bind_address] [-f config_file]",
" [-l [mode:]path] [-m mark_interval]", " [-l [mode:]path] [-m mark_interval]",
" [-P pid_file] [-p log_socket]", " [-P pid_file] [-p log_socket]",
@ -845,28 +846,43 @@ usage(void)
} }
/* /*
* Take a raw input line, decode the message, and print the message * Take a raw input line, extract PRI, TIMESTAMP and HOSTNAME from the message,
* on the appropriate log files. * and print the message on the appropriate log files.
*/ */
static void static void
printline(const char *hname, char *msg, int flags) parsemsg(const char *from, char *msg)
{ {
char *p, *q; const char *timestamp;
char *q;
long n; long n;
int c, pri; int i, c, pri, msglen;
char line[MAXLINE + 1]; char line[MAXLINE + 1];
/* test for special codes */ /* Parse PRI. */
p = msg; if (msg[0] != '<' || !isdigit(msg[1])) {
pri = DEFUPRI; dprintf("Invalid PRI from %s\n", from);
if (*p == '<') { return;
}
for (i = 2; i <= 4; i++) {
if (msg[i] == '>')
break;
if (!isdigit(msg[i])) {
dprintf("Invalid PRI header from %s\n", from);
return;
}
}
if (msg[i] != '>') {
dprintf("Invalid PRI header from %s\n", from);
return;
}
errno = 0; errno = 0;
n = strtol(p + 1, &q, 10); n = strtol(msg + 1, &q, 10);
if (*q == '>' && n >= 0 && n < INT_MAX && errno == 0) { if (errno != 0 || *q != msg[i] || n < 0 || n >= INT_MAX) {
p = q + 1; dprintf("Invalid PRI %ld from %s: %s\n",
n, from, strerror(errno));
return;
}
pri = n; pri = n;
}
}
if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
pri = DEFUPRI; pri = DEFUPRI;
@ -878,9 +894,53 @@ printline(const char *hname, char *msg, int flags)
if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac) if ((pri & LOG_FACMASK) == LOG_KERN && !KeepKernFac)
pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
q = line; /*
* The TIMESTAMP field is the local time and is in the format of
* "Mmm dd hh:mm:ss" (without the quote marks).
* A single space character MUST follow the TIMESTAMP field.
*
* XXXGL: the check can be improved.
*/
msg += i + 1;
msglen = strlen(msg);
if (msglen < MAXDATELEN || msg[3] != ' ' || msg[6] != ' ' ||
msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
dprintf("Invalid TIMESTAMP from %s: %s\n", from, msg);
return;
}
while ((c = (unsigned char)*p++) != '\0' && if (!RemoteAddDate)
timestamp = msg;
else
timestamp = NULL;
msg += MAXDATELEN;
msglen -= MAXDATELEN;
/*
* A single space character MUST also follow the HOSTNAME field.
*/
for (i = 0; i < MIN(MAXHOSTNAMELEN, msglen); i++) {
if (msg[i] == ' ') {
if (RemoteHostname) {
msg[i] = '\0';
from = msg;
}
msg += i + 1;
break;
}
/*
* Support non RFC compliant messages, without hostname.
*/
if (msg[i] == ':')
break;
}
if (i == MIN(MAXHOSTNAMELEN, msglen)) {
dprintf("Invalid HOSTNAME from %s: %s\n", from, msg);
return;
}
q = line;
while ((c = (unsigned char)*msg++) != '\0' &&
q < &line[sizeof(line) - 4]) { q < &line[sizeof(line) - 4]) {
if (mask_C1 && (c & 0x80) && c < 0xA0) { if (mask_C1 && (c & 0x80) && c < 0xA0) {
c &= 0x7F; c &= 0x7F;
@ -902,7 +962,7 @@ printline(const char *hname, char *msg, int flags)
} }
*q = '\0'; *q = '\0';
logmsg(pri, line, hname, flags); logmsg(pri, timestamp, line, from, 0);
} }
/* /*
@ -956,7 +1016,7 @@ printsys(char *msg)
long n; long n;
int flags, isprintf, pri; int flags, isprintf, pri;
flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */ flags = ISKERNEL | SYNC_FILE; /* fsync after write */
p = msg; p = msg;
pri = DEFSPRI; pri = DEFSPRI;
isprintf = 1; isprintf = 1;
@ -977,7 +1037,7 @@ printsys(char *msg)
flags |= IGN_CONS; flags |= IGN_CONS;
if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
pri = DEFSPRI; pri = DEFSPRI;
logmsg(pri, p, LocalHostName, flags); logmsg(pri, NULL, p, LocalHostName, flags);
} }
static time_t now; static time_t now;
@ -1032,39 +1092,20 @@ skip_message(const char *name, const char *spec, int checkcase)
* the priority. * the priority.
*/ */
static void static void
logmsg(int pri, const char *msg, const char *from, int flags) logmsg(int pri, const char *timestamp, const char *msg, const char *from,
int flags)
{ {
struct filed *f; struct filed *f;
int i, fac, msglen, prilev; int i, fac, msglen, prilev;
const char *timestamp;
char prog[NAME_MAX+1]; char prog[NAME_MAX+1];
char buf[MAXLINE+1]; char buf[MAXLINE+1];
dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
pri, flags, from, msg); pri, flags, from, msg);
/*
* Check to see if msg looks non-standard.
*/
msglen = strlen(msg);
if (msglen < MAXDATELEN || msg[3] != ' ' || msg[6] != ' ' ||
msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
flags |= ADDDATE;
(void)time(&now); (void)time(&now);
if (flags & ADDDATE) { if (timestamp == NULL)
timestamp = ctime(&now) + 4; timestamp = ctime(&now) + 4;
} else {
timestamp = msg;
msg += MAXDATELEN;
msglen -= MAXDATELEN;
}
/* skip leading blanks */
while (isspace(*msg)) {
msg++;
msglen--;
}
/* extract facility and priority level */ /* extract facility and priority level */
if (flags & MARK) if (flags & MARK)
@ -1078,7 +1119,7 @@ logmsg(int pri, const char *msg, const char *from, int flags)
prilev = LOG_PRI(pri); prilev = LOG_PRI(pri);
/* extract program name */ /* Extract TAG part of the message (usually program name). */
for (i = 0; i < NAME_MAX; i++) { for (i = 0; i < NAME_MAX; i++) {
if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' || if (!isprint(msg[i]) || msg[i] == ':' || msg[i] == '[' ||
msg[i] == '/' || isspace(msg[i])) msg[i] == '/' || isspace(msg[i]))
@ -1092,8 +1133,8 @@ logmsg(int pri, const char *msg, const char *from, int flags)
snprintf(buf, sizeof(buf), "%s: %s", snprintf(buf, sizeof(buf), "%s: %s",
use_bootfile ? bootfile : "kernel", msg); use_bootfile ? bootfile : "kernel", msg);
msg = buf; msg = buf;
msglen = strlen(buf);
} }
msglen = strlen(msg);
/* log the message to the particular outputs */ /* log the message to the particular outputs */
if (!Initialized) { if (!Initialized) {
@ -1643,7 +1684,7 @@ logerror(const char *type)
(void)snprintf(buf, sizeof buf, "syslogd: %s", type); (void)snprintf(buf, sizeof buf, "syslogd: %s", type);
errno = 0; errno = 0;
dprintf("%s\n", buf); dprintf("%s\n", buf);
logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); logmsg(LOG_SYSLOG|LOG_ERR, NULL, buf, LocalHostName, 0);
recursed--; recursed--;
} }
@ -1987,7 +2028,7 @@ init(int signo)
} }
} }
logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); logmsg(LOG_SYSLOG|LOG_INFO, NULL, "syslogd: restart", LocalHostName, 0);
dprintf("syslogd: restarted\n"); dprintf("syslogd: restarted\n");
/* /*
* Log a change in hostname, but only on a restart. * Log a change in hostname, but only on a restart.
@ -1996,7 +2037,7 @@ init(int signo)
(void)snprintf(hostMsg, sizeof(hostMsg), (void)snprintf(hostMsg, sizeof(hostMsg),
"syslogd: hostname changed, \"%s\" to \"%s\"", "syslogd: hostname changed, \"%s\" to \"%s\"",
oldLocalHostName, LocalHostName); oldLocalHostName, LocalHostName);
logmsg(LOG_SYSLOG|LOG_INFO, hostMsg, LocalHostName, ADDDATE); logmsg(LOG_SYSLOG|LOG_INFO, NULL, hostMsg, LocalHostName, 0);
dprintf("%s\n", hostMsg); dprintf("%s\n", hostMsg);
} }
/* /*
@ -2006,7 +2047,7 @@ init(int signo)
if (signo == 0 && !use_bootfile) { if (signo == 0 && !use_bootfile) {
(void)snprintf(bootfileMsg, sizeof(bootfileMsg), (void)snprintf(bootfileMsg, sizeof(bootfileMsg),
"syslogd: kernel boot file is %s", bootfile); "syslogd: kernel boot file is %s", bootfile);
logmsg(LOG_KERN|LOG_INFO, bootfileMsg, LocalHostName, ADDDATE); logmsg(LOG_KERN|LOG_INFO, NULL, bootfileMsg, LocalHostName, 0);
dprintf("%s\n", bootfileMsg); dprintf("%s\n", bootfileMsg);
} }
} }
@ -2315,8 +2356,7 @@ markit(void)
now = time((time_t *)NULL); now = time((time_t *)NULL);
MarkSeq += TIMERINTVL; MarkSeq += TIMERINTVL;
if (MarkSeq >= MarkInterval) { if (MarkSeq >= MarkInterval) {
logmsg(LOG_INFO, "-- MARK --", logmsg(LOG_INFO, NULL, "-- MARK --", LocalHostName, MARK);
LocalHostName, ADDDATE|MARK);
MarkSeq = 0; MarkSeq = 0;
} }