On Fri, 28 Apr 2006, Brian wrote:
> I am in the process of making syslogd more protocol independent (IPv4
> & IPv6). I am just about ready to add a priviledged fuction for
> getnameinfo, but what I do not understand is why the the DNS lookups
> are priviledged separated. I do understand the security piece talked
> about in the getnameinfo(3) man page. And I have read through the CVS
> comments.
Unless you are doing it for education or fun, then don't bother making
syslogd IPv6 capable - there is already a patch (see below).
The DNS lookups are privilege separated because the unprivileged
child will not have access to /etc/resolv.conf, /etc/hosts, etc.
If it passes them back up to the monitor, then the monitor will have
access to these files and will be able to make the lookups normally.
-d
----------------------------
IPv6 syslogd patch from Mischa Diehm <[EMAIL PROTECTED]>. It might be a little
stale, as it is around a year old now.
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/Makefile,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile
--- Makefile 4 Jan 2004 08:28:49 -0000 1.5
+++ Makefile 6 Aug 2005 19:02:57 -0000
@@ -4,4 +4,13 @@ PROG= syslogd
SRCS= syslogd.c ttymsg.c privsep.c privsep_fdpass.c ringbuf.c
MAN= syslogd.8 syslog.conf.5
+CDIAGFLAGS= -Wall
+CDIAGFLAGS+= -Wpointer-arith
+CDIAGFLAGS+= -Wno-uninitialized
+CDIAGFLAGS+= -Wstrict-prototypes
+CDIAGFLAGS+= -Wmissing-prototypes
+CDIAGFLAGS+= -Wunused
+CDIAGFLAGS+= -Wbounded
+CDIAGFLAGS+= -Wshadow
+
.include <bsd.prog.mk>
Index: privsep.c
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/privsep.c,v
retrieving revision 1.26
diff -u -p -r1.26 privsep.c
--- privsep.c 6 Jun 2005 23:20:44 -0000 1.26
+++ privsep.c 6 Aug 2005 19:02:57 -0000
@@ -66,8 +66,8 @@ enum cmd_types {
PRIV_OPEN_UTMP, /* open utmp for reading only */
PRIV_OPEN_CONFIG, /* open config file for reading only */
PRIV_CONFIG_MODIFIED, /* check if config file has been modified */
- PRIV_GETHOSTSERV, /* resolve host/service names */
- PRIV_GETHOSTBYADDR, /* resolve numeric address into hostname */
+ PRIV_GETADDRINFO, /* resolve hostname into numerical address */
+ PRIV_GETNAMEINFO, /* resolve numeric address into hostname */
PRIV_DONE_CONFIG_PARSE /* signal that the initial config parse is done
*/
};
@@ -75,7 +75,7 @@ static int priv_fd = -1;
static volatile pid_t child_pid = -1;
static char config_file[MAXPATHLEN];
static struct stat cf_info;
-static int allow_gethostbyaddr = 0;
+static int allow_getnameinfo = 0;
static volatile sig_atomic_t cur_state = STATE_INIT;
/* Queue for the allowed logfiles */
@@ -97,14 +97,14 @@ static int may_read(int, void *, size_t
int
priv_init(char *conf, int numeric, int lockfd, int nullfd, char *argv[])
{
- int i, fd, socks[2], cmd, addr_len, addr_af, result, restart;
+ int i, fd, socks[2], cmd, addr_len, result, restart, error;
size_t path_len, hostname_len, servname_len;
- char path[MAXPATHLEN], hostname[MAXHOSTNAMELEN];
- char servname[MAXHOSTNAMELEN];
+ char path[MAXPATHLEN], host[NI_MAXHOST];
+ char hostname[NI_MAXHOST], servname[NI_MAXSERV];
struct stat cf_stat;
- struct hostent *hp;
struct passwd *pw;
- struct addrinfo hints, *res0;
+ struct addrinfo hints, *res, *r;
+ struct sockaddr_storage s_addr;
for (i = 1; i < _NSIG; i++)
signal(i, SIG_DFL);
@@ -164,8 +164,9 @@ priv_init(char *conf, int numeric, int l
for (i = 0; i < nfunix; i++)
if (pfd[PFD_UNIX_0 + i].fd != -1)
close(pfd[PFD_UNIX_0 + i].fd);
- if (pfd[PFD_INET].fd != -1)
- close(pfd[PFD_INET].fd);
+ for (i = 0; i < nfinet; i++)
+ if (pfd[start_inetfds + i].fd != -1)
+ close(pfd[start_inetfds + i].fd);
if (pfd[PFD_CTLSOCK].fd != -1)
close(pfd[PFD_CTLSOCK].fd);
if (pfd[PFD_CTLCONN].fd != -1)
@@ -180,11 +181,11 @@ priv_init(char *conf, int numeric, int l
if (stat(config_file, &cf_info) < 0)
err(1, "stat config file failed");
- /* Save whether or not the child can have access to gethostbyaddr(3) */
+ /* Save whether or not the child can have access to getnameinfo(3) */
if (numeric > 0)
- allow_gethostbyaddr = 0;
+ allow_getnameinfo = 0;
else
- allow_gethostbyaddr = 1;
+ allow_getnameinfo = 1;
TAILQ_INIT(&lognames);
increase_state(STATE_CONFIG);
@@ -269,57 +270,91 @@ priv_init(char *conf, int numeric, int l
increase_state(STATE_RUNNING);
break;
- case PRIV_GETHOSTSERV:
- dprintf("[priv]: msg PRIV_GETHOSTSERV received\n");
- /* Expecting: len, hostname, len, servname */
+ case PRIV_GETADDRINFO:
+ dprintf("[priv]: msg PRIV_GETADDRINFO received\n");
+
+ /* Expecting: length, hostname, length, servname */
must_read(socks[0], &hostname_len, sizeof(size_t));
- if (hostname_len == 0 || hostname_len >
sizeof(hostname))
+ if (hostname_len == 0 ||
+ hostname_len > sizeof(hostname)) {
+ dprintf("[priv]: PRIV_GETADDRINFO bad len %d\n",
+ hostname_len);
_exit(0);
+ }
must_read(socks[0], &hostname, hostname_len);
hostname[hostname_len - 1] = '\0';
-
must_read(socks[0], &servname_len, sizeof(size_t));
- if (servname_len == 0 || servname_len >
sizeof(servname))
+ if (servname_len == 0 ||
+ servname_len > sizeof(servname))
_exit(0);
must_read(socks[0], &servname, servname_len);
servname[servname_len - 1] = '\0';
- memset(&hints, '\0', sizeof(hints));
- hints.ai_family = AF_INET;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = af;
hints.ai_socktype = SOCK_DGRAM;
- i = getaddrinfo(hostname, servname, &hints, &res0);
- if (i != 0 || res0 == NULL) {
+ error = getaddrinfo(hostname, servname, &hints, &res);
+ if (error) {
+ warnx("getaddrinfo failed: %s",
+ gai_strerror(error));
addr_len = 0;
must_write(socks[0], &addr_len, sizeof(int));
} else {
- /* Just send the first address */
- i = res0->ai_addrlen;
- must_write(socks[0], &i, sizeof(int));
- must_write(socks[0], res0->ai_addr, i);
- freeaddrinfo(res0);
+ int num = 0;
+
+ for (r = res; r != NULL; r = r->ai_next)
+ num++;
+
+ /* limit the number of returned addresses */
+ if (num > MAX_GETADDR) {
+ dprintf("[priv]: Getaddrinfo returned "
+ "%d addresses. Limiting to %d.\n",
+ num, MAX_GETADDR);
+ num = MAX_GETADDR;
+ }
+ must_write(socks[0], &num, sizeof(int));
+ for (r = res; num > 0; r = r->ai_next) {
+ must_write(socks[0], &r->ai_addrlen,
+ sizeof(socklen_t));
+ must_write(socks[0], r->ai_addr,
+ r->ai_addrlen);
+ num--;
+ }
+ freeaddrinfo(res);
}
break;
- case PRIV_GETHOSTBYADDR:
- dprintf("[priv]: msg PRIV_GETHOSTBYADDR received\n");
- if (!allow_gethostbyaddr)
- errx(1, "rejected attempt to gethostbyaddr");
- /* Expecting: length, address, address family */
+ case PRIV_GETNAMEINFO:
+ dprintf("[priv]: msg PRIV_GETNAMEINFO received\n");
+ if (!allow_getnameinfo)
+ errx(1, "rejected attempt to getnameinfo");
+
+ /* Expecting: length, sockaddr */
must_read(socks[0], &addr_len, sizeof(int));
- if (addr_len <= 0 || addr_len > sizeof(hostname))
+ if (addr_len <= 0 ||
+ addr_len > sizeof(struct sockaddr_storage)) {
+ dprintf("[priv]: PRIV_GETNAMEINFO bad len %d\n",
+ addr_len);
_exit(0);
- must_read(socks[0], hostname, addr_len);
- must_read(socks[0], &addr_af, sizeof(int));
- hp = gethostbyaddr(hostname, addr_len, addr_af);
- if (hp == NULL) {
+ }
+ must_read(socks[0], &s_addr, addr_len);
+
+ error = getnameinfo((struct sockaddr*)&s_addr,
+ ((struct sockaddr*)&s_addr)->sa_len,
+ host, sizeof(host), NULL, 0, NI_DGRAM);
+
+ if (error) {
+ warnx("getnameinfo failed: %s",
+ gai_strerror(error));
addr_len = 0;
must_write(socks[0], &addr_len, sizeof(int));
} else {
- addr_len = strlen(hp->h_name) + 1;
+ addr_len = strlen(host) + 1;
must_write(socks[0], &addr_len, sizeof(int));
- must_write(socks[0], hp->h_name, addr_len);
+ must_write(socks[0], host, addr_len);
}
break;
+
default:
errx(1, "unknown command %d", cmd);
break;
@@ -336,9 +371,9 @@ priv_init(char *conf, int numeric, int l
(void)unlink(ctlsock_path);
if (restart) {
- int r;
+ int status;
- wait(&r);
+ wait(&status);
execvp(argv[0], argv);
}
_exit(1);
@@ -555,63 +590,67 @@ priv_config_parse_done(void)
/* Name/service to address translation. Response is placed into addr, and
* the length is returned (zero on error) */
int
-priv_gethostserv(char *host, char *serv, struct sockaddr *addr,
- size_t addr_len)
+priv_getaddrinfo(char *host, char *servname, struct sockaddr **s_addr)
{
- char hostcpy[MAXHOSTNAMELEN], servcpy[MAXHOSTNAMELEN];
- int cmd, ret_len;
+ int cmd, i, num = 0;
+ char hostcpy[NI_MAXHOST];
+ char servnamecpy[NI_MAXSERV];
size_t hostname_len, servname_len;
+ socklen_t addr_len;
+ struct sockaddr_storage *tmp_ss;
if (priv_fd < 0)
- errx(1, "%s: called from privileged portion",
"priv_gethostserv");
+ errx(1, "priv_getaddrinfo: called from privileged portion");
if (strlcpy(hostcpy, host, sizeof hostcpy) >= sizeof(hostcpy))
- errx(1, "%s: overflow attempt in hostname", "priv_gethostserv");
+ errx(1, "priv_getaddrinfo: overflow attempt in hostname");
hostname_len = strlen(hostcpy) + 1;
- if (strlcpy(servcpy, serv, sizeof servcpy) >= sizeof(servcpy))
- errx(1, "%s: overflow attempt in servname", "priv_gethostserv");
- servname_len = strlen(servcpy) + 1;
+ if (strlcpy(servnamecpy, servname, sizeof servnamecpy) >=
+ sizeof(servnamecpy))
+ errx(1, "priv_getaddrinfo: overflow attempt in servname");
+ servname_len = strlen(servnamecpy) + 1;
- cmd = PRIV_GETHOSTSERV;
+ cmd = PRIV_GETADDRINFO;
must_write(priv_fd, &cmd, sizeof(int));
must_write(priv_fd, &hostname_len, sizeof(size_t));
must_write(priv_fd, hostcpy, hostname_len);
must_write(priv_fd, &servname_len, sizeof(size_t));
- must_write(priv_fd, servcpy, servname_len);
+ must_write(priv_fd, servnamecpy, servname_len);
- /* Expect back an integer size, and then a string of that length */
- must_read(priv_fd, &ret_len, sizeof(int));
+ /* Expect back an integer with the number of sockaddr(s) */
+ must_read(priv_fd, &num, sizeof(int));
- /* Check there was no error (indicated by a return of 0) */
- if (!ret_len)
- return 0;
+ if (num <= 0)
+ return (0);
- /* Make sure we aren't overflowing the passed in buffer */
- if (addr_len < ret_len)
- errx(1, "%s: overflow attempt in return", "priv_gethostserv");
-
- /* Read the resolved address and make sure we got all of it */
- memset(addr, '\0', addr_len);
- must_read(priv_fd, addr, ret_len);
-
- return ret_len;
+ if ((*s_addr = malloc(num * sizeof(struct sockaddr_storage))) == NULL)
+ err(1, "priv_getaddrinfo() malloc");
+
+ /* Read the returned address structure(s) */
+ tmp_ss = (struct sockaddr_storage *)*s_addr;
+ for (i = 0; i < num; i++) {
+ must_read(priv_fd, &addr_len, sizeof(socklen_t));
+ must_read(priv_fd, &(tmp_ss[i]), addr_len);
+ }
+ return num;
}
/* Reverse address resolution; response is placed into res, and length of
* response is returned (zero on error) */
int
-priv_gethostbyaddr(char *addr, int addr_len, int af, char *res, size_t res_len)
+priv_getnameinfo(struct sockaddr *s_addr, char *res, size_t res_len)
{
- int cmd, ret_len;
+ int cmd, ret_len, addr_len;
+
+ addr_len = s_addr->sa_len;
if (priv_fd < 0)
- errx(1, "%s called from privileged portion",
"priv_gethostbyaddr");
+ errx(1, "%s called from privileged portion",
"priv_getnameinfo");
- cmd = PRIV_GETHOSTBYADDR;
+ cmd = PRIV_GETNAMEINFO;
must_write(priv_fd, &cmd, sizeof(int));
must_write(priv_fd, &addr_len, sizeof(int));
- must_write(priv_fd, addr, addr_len);
- must_write(priv_fd, &af, sizeof(int));
+ must_write(priv_fd, s_addr, addr_len);
/* Expect back an integer size, and then a string of that length */
must_read(priv_fd, &ret_len, sizeof(int));
@@ -622,7 +661,7 @@ priv_gethostbyaddr(char *addr, int addr_
/* Check we don't overflow the passed in buffer */
if (res_len < ret_len)
- errx(1, "%s: overflow attempt in return", "priv_gethostbyaddr");
+ errx(1, "%s: overflow attempt in return", "priv_getnameinfo");
/* Read the resolved hostname */
must_read(priv_fd, res, ret_len);
@@ -677,7 +716,8 @@ static void
must_read(int fd, void *buf, size_t n)
{
char *s = buf;
- ssize_t res, pos = 0;
+ ssize_t res;
+ size_t pos = 0;
while (n > pos) {
res = read(fd, s + pos, n - pos);
@@ -699,7 +739,8 @@ static void
must_write(int fd, void *buf, size_t n)
{
char *s = buf;
- ssize_t res, pos = 0;
+ ssize_t res;
+ size_t pos = 0;
while (n > pos) {
res = write(fd, s + pos, n - pos);
Index: syslogd.8
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.8,v
retrieving revision 1.21
diff -u -p -r1.21 syslogd.8
--- syslogd.8 2 Dec 2004 21:58:57 -0000 1.21
+++ syslogd.8 6 Aug 2005 19:02:57 -0000
@@ -39,7 +39,7 @@
.Sh SYNOPSIS
.Nm syslogd
.Bk -words
-.Op Fl dnu
+.Op Fl 46dnu
.Op Fl a Ar path
.Op Fl f Ar config_file
.Op Fl m Ar mark_interval
@@ -53,6 +53,14 @@ machines and/or users as specified by it
.Pp
The options are as follows:
.Bl -tag -width Ds
+.It Fl 4
+Force
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Force
+.Nm
+to use IPv6 addresses only.
.It Fl a Pa path
Specify a location where
.Nm
@@ -73,7 +81,7 @@ Select the number of minutes between
.Dq mark
messages; the default is 20 minutes.
.It Fl n
-Print source addresses numerically rather than symbolically.
+Print values for loghosts as defined in the configuration file.
This saves an address-to-name lookup for each incoming message,
which can be useful when combined with the
.Fl u
Index: syslogd.c
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.c,v
retrieving revision 1.92
diff -u -p -r1.92 syslogd.c
--- syslogd.c 10 Jun 2005 01:41:43 -0000 1.92
+++ syslogd.c 6 Aug 2005 19:02:58 -0000
@@ -141,8 +141,11 @@ struct filed {
union {
char f_uname[MAXUNAMES][UT_NAMESIZE+1];
struct {
- char f_hname[MAXHOSTNAMELEN];
- struct sockaddr_storage f_addr;
+ char f_host[NI_MAXHOST];
+ char f_serv[NI_MAXSERV];
+ int f_num_addrs;
+ struct sockaddr_storage *f_addrs;
+ int f_good_addr;
} f_forw; /* forwarding address */
char f_fname[MAXPATHLEN];
struct {
@@ -153,7 +156,7 @@ struct filed {
} f_un;
char f_prevline[MAXSVLINE]; /* last message logged */
char f_lasttime[16]; /* time of last occurrence */
- char f_prevhost[MAXHOSTNAMELEN]; /* host from which recd. */
+ char f_prevhost[NI_MAXHOST]; /* host from which recd. */
int f_prevpri; /* pri of f_prevline */
int f_prevlen; /* length of f_prevline */
int f_prevcount; /* repetition cnt of prevline */
@@ -192,10 +195,12 @@ struct filed *Files;
struct filed consfile;
int nfunix = 1; /* Number of Unix domain sockets requested */
+int nfinet = 0; /* Number of Inet domain sockets requested */
+int start_inetfds = 0; /* Offset for Internet datagram sockets */
char *funixn[MAXFUNIX] = { _PATH_LOG }; /* Paths to Unix domain sockets */
int Debug; /* debug flag */
int Startup = 1; /* startup flag */
-char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */
+char LocalHostName[NI_MAXHOST]; /* our hostname */
char *LocalDomain; /* our local domain name */
int InetInuse = 0; /* non-zero if INET sockets are being used */
int LogPort; /* port number for INET connections */
@@ -206,6 +211,8 @@ int MarkSeq = 0; /* mark sequence numbe
int SecureMode = 1; /* when true, speak only unix domain socks */
int NoDNS = 0; /* when true, will refrain from doing DNS
lookups */
+int af = AF_UNSPEC; /* address family for inet-socket */
+
char *ctlsock_path = NULL; /* Path to control socket */
#define CTL_READING_CMD 1
@@ -247,13 +254,14 @@ size_t ctl_reply_size = 0; /* Number of
size_t ctl_reply_offset = 0; /* Number of bytes of reply written so far */
struct pollfd pfd[N_PFD];
+int pollfd_ai_fam[MAX_AI_PASSIVE];
volatile sig_atomic_t MarkSet;
volatile sig_atomic_t WantDie;
volatile sig_atomic_t DoInit;
struct filed *cfline(char *, char *);
-void cvthname(struct sockaddr_in *, char *, size_t);
+void cvthname(struct sockaddr *, char *, size_t);
int decode(const char *, const CODE *);
void dodie(int);
void doinit(int);
@@ -281,17 +289,25 @@ void ctlconn_write_handler(void);
int
main(int argc, char *argv[])
{
- int ch, i, linesize, fd;
+ int ch, error, fd, i, linesize, maxs, nfds;
+ const int on = 1;
+ FILE *fp;
struct sockaddr_un fromunix;
- struct sockaddr_in s_in, frominet;
+ struct addrinfo hints, *res, *r;
+ struct sockaddr_storage frominet;
socklen_t len;
char *p, *line;
- char resolve[MAXHOSTNAMELEN];
+ char resolve[NI_MAXHOST];
int lockpipe[2], nullfd;
- FILE *fp;
- while ((ch = getopt(argc, argv, "dnuf:m:p:a:s:")) != -1)
+ while ((ch = getopt(argc, argv, "46dnuf:m:p:a:s:")) != -1)
switch (ch) {
+ case '4': /* IPv4 only */
+ af = AF_INET;
+ break;
+ case '6': /* IPv6 only */
+ af = AF_INET6;
+ break;
case 'd': /* debug */
Debug++;
break;
@@ -359,41 +375,69 @@ main(int argc, char *argv[])
}
/* Clear poll array, set all fds to ignore */
- for (i = 0; i < N_PFD; i++) {
+ for (i = 0; i < MAX_AI_PASSIVE; i++) {
pfd[i].fd = -1;
pfd[i].events = 0;
}
- if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) != -1) {
- struct servent *sp;
+ /* setup listening sockets */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo(NULL, "syslog", &hints, &res);
+ if (error) {
+ logerror(gai_strerror(error));
+ errno = 0;
+ die(0);
+ }
- /* XXX use getaddrinfo */
- sp = getservbyname("syslog", "udp");
- if (sp == NULL) {
- errno = 0;
- logerror("syslog/udp: unknown service");
- die(0);
+ /* Count max number of sockets we may open */
+ for (maxs = 0, r = res; r; r = r->ai_next, maxs++) {
+ if (maxs >= MAX_AI_PASSIVE) {
+ dprintf("Too may listening sockets returned!\
+ Using maximum of (%d) sockets\n", MAX_AI_PASSIVE);
}
- memset(&s_in, 0, sizeof(s_in));
- s_in.sin_len = sizeof(s_in);
- s_in.sin_family = AF_INET;
- s_in.sin_port = LogPort = sp->s_port;
- if (bind(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) {
- logerror("bind");
- if (!Debug)
- die(0);
+ }
+
+ start_inetfds = PFD_UNIX_0 + nfunix;
+ i = 0;
+ for (r = res; r && i < MAX_AI_PASSIVE; r = r->ai_next, i++) {
+ fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
+ if (fd < 0) {
+ logerror("socket() failed");
+ continue;
+ }
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on,
+ sizeof(on)) < 0) {
+ logerror("setsockopt(REUSEADDR) failed");
+ close(fd);
+ continue;
+ }
+ if (bind(fd, r->ai_addr, r->ai_addrlen) < 0) {
+ logerror("bind() failed");
+ close(fd);
+ continue;
} else {
- InetInuse = 1;
- pfd[PFD_INET].fd = fd;
+ pfd[start_inetfds + i].fd = fd;
+ nfinet++;
if (SecureMode) {
- shutdown(fd, SHUT_RD);
+ if (shutdown(fd, SHUT_RD) == -1) {
+ logerror("shutdown() failed");
+ die(0);
+ }
} else {
double_rbuf(fd);
- pfd[PFD_INET].events = POLLIN;
+ pfd[start_inetfds + i].events = POLLIN;
+ pollfd_ai_fam[i] = r->ai_family;
}
}
+ InetInuse = 1;
}
+ if (res)
+ freeaddrinfo(res);
+
#ifndef SUN_LEN
#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
#endif
@@ -513,7 +557,8 @@ main(int argc, char *argv[])
DoInit = 0;
}
- switch (poll(pfd, PFD_UNIX_0 + nfunix, -1)) {
+ nfds = PFD_UNIX_0 + nfunix + nfinet;
+ switch (poll(pfd, nfds, -1)) {
case 0:
continue;
case -1:
@@ -533,19 +578,6 @@ main(int argc, char *argv[])
pfd[PFD_KLOG].events = 0;
}
}
- if ((pfd[PFD_INET].revents & POLLIN) != 0) {
- len = sizeof(frominet);
- i = recvfrom(pfd[PFD_INET].fd, line, MAXLINE, 0,
- (struct sockaddr *)&frominet, &len);
- if (i > 0) {
- line[i] = '\0';
- cvthname(&frominet, resolve,
- sizeof resolve);
- dprintf("cvthname res: %s\n", resolve);
- printline(resolve, line);
- } else if (i < 0 && errno != EINTR)
- logerror("recvfrom inet");
- }
if ((pfd[PFD_CTLSOCK].revents & POLLIN) != 0)
ctlsock_accept_handler();
if ((pfd[PFD_CTLCONN].revents & POLLIN) != 0)
@@ -568,6 +600,23 @@ main(int argc, char *argv[])
logerror("recvfrom unix");
}
}
+
+ for (i = 0; SecureMode && i < nfinet; i++) {
+ if ((pfd[start_inetfds + i].revents & POLLIN) != 0) {
+ len = sizeof(frominet);
+ i = recvfrom(pfd[start_inetfds + i].fd, line,
+ MAXLINE, 0, (struct sockaddr *)&frominet,
+ &len);
+ if (i > 0) {
+ line[i] = '\0';
+ cvthname((struct sockaddr *)&frominet,
+ resolve, sizeof(resolve));
+ dprintf("cvthname res: %s\n", resolve);
+ printline(resolve, line);
+ } else if (i < 0 && errno != EINTR)
+ logerror("recvfrom inet");
+ }
+ }
}
/* NOTREACHED */
free(pfd);
@@ -579,8 +628,9 @@ usage(void)
{
(void)fprintf(stderr,
- "usage: syslogd [-dnu] [-a path] [-f config_file] [-m
mark_interval]\n"
- " [-p log_socket] [-s reporting_socket]\n");
+ "usage: syslogd [-dnu46] [-a path] [-f config_file]\n"
+ " [-m mark_interval] [-p log_socket]\n"
+ " [-s reporting_socket]\n");
exit(1);
}
@@ -799,8 +849,9 @@ fprintlog(struct filed *f, int flags, ch
{
struct iovec iov[6];
struct iovec *v;
- int l, retryonce;
+ int i, j, l, len, n, ok, retryonce;
char line[MAXLINE + 1], repbuf[80], greetings[500];
+ struct sockaddr_storage *addr;
v = iov;
if (f->f_type == F_WALL) {
@@ -855,26 +906,50 @@ fprintlog(struct filed *f, int flags, ch
break;
case F_FORW:
- dprintf(" %s\n", f->f_un.f_forw.f_hname);
+ dprintf(" %s:%s\n", f->f_un.f_forw.f_host,
+ f->f_un.f_forw.f_serv);
if ((l = snprintf(line, sizeof(line), "<%d>%.15s %s",
f->f_prevpri, (char *)iov[0].iov_base,
(char *)iov[4].iov_base)) >= sizeof(line) || l == -1)
l = strlen(line);
- if (sendto(pfd[PFD_INET].fd, line, l, 0,
- (struct sockaddr *)&f->f_un.f_forw.f_addr,
- f->f_un.f_forw.f_addr.ss_len) != l) {
- switch (errno) {
- case EHOSTDOWN:
- case EHOSTUNREACH:
- case ENETDOWN:
- case ENOBUFS:
- /* silently dropped */
- break;
- default:
- f->f_type = F_UNUSED;
- logerror("sendto");
- break;
+ ok = 0;
+ for (i = 0; i < f->f_un.f_forw.f_num_addrs; i++) {
+ /*
+ * Try all addresses, starting with the
+ * last known good one.
+ */
+ n = (f->f_un.f_forw.f_good_addr + i) %
+ f->f_un.f_forw.f_num_addrs;
+ addr = &(f->f_un.f_forw.f_addrs[n]);
+
+ for (j = 0; j < nfinet; j++) {
+ if (addr->ss_family != pollfd_ai_fam[j])
+ continue;
+ len = f->f_un.f_forw.f_addrs[n].ss_len;
+ if (sendto(pfd[start_inetfds + j].fd, line, l,
+ 0, (struct sockaddr *)addr, len) == l) {
+ f->f_un.f_forw.f_good_addr += i;
+ ok = 1;
+ break;
+ } else {
+ switch (errno) {
+ case EHOSTDOWN:
+ case EHOSTUNREACH:
+ case ENETDOWN:
+ case ENOBUFS:
+ /* silently dropped */
+ continue;
+ default:
+ f->f_type = F_UNUSED;
+ f->f_un.f_forw.f_num_addrs = 0;
+ free(f->f_un.f_forw.f_addrs);
+ f->f_un.f_forw.f_addrs = NULL;
+ logerror("sendto() failed");
+ }
+ }
}
+ if (ok)
+ break;
}
break;
@@ -939,7 +1014,7 @@ fprintlog(struct filed *f, int flags, ch
case F_MEMBUF:
dprintf("\n");
snprintf(line, sizeof(line), "%.15s %s %s",
- (char *)iov[0].iov_base, (char *)iov[2].iov_base,
+ (char *)iov[0].iov_base, (char *)iov[2].iov_base,
(char *)iov[4].iov_base);
if (ringbuf_append_line(f->f_un.f_mb.f_rb, line) == 1)
f->f_un.f_mb.f_overflow = 1;
@@ -1019,19 +1094,27 @@ reapchild(int signo)
* Return a printable representation of a host address.
*/
void
-cvthname(struct sockaddr_in *f, char *result, size_t res_len)
+cvthname(struct sockaddr *f, char *result, size_t res_len)
{
sigset_t omask, nmask;
- char *p, *ip;
int ret_len;
+ char *p;
+ int error;
+ char ip[NI_MAXHOST];
- if (f->sin_family != AF_INET) {
- dprintf("Malformed from address\n");
+ if (f->sa_family != AF_INET && f->sa_family != AF_INET6) {
+ dprintf("Unsupport from address family\n");
+ strlcpy(result, "???", res_len);
+ return;
+ }
+
+ if ((error = getnameinfo(f, f->sa_len, ip, sizeof(ip), NULL, 0,
+ NI_NUMERICHOST|NI_DGRAM)) != 0) {
+ dprintf("Malformed from address: %s\n", gai_strerror(error));
strlcpy(result, "???", res_len);
return;
}
- ip = inet_ntoa(f->sin_addr);
dprintf("cvthname(%s)\n", ip);
if (NoDNS) {
strlcpy(result, ip, res_len);
@@ -1042,8 +1125,7 @@ cvthname(struct sockaddr_in *f, char *re
sigaddset(&nmask, SIGHUP);
sigprocmask(SIG_BLOCK, &nmask, &omask);
- ret_len = priv_gethostbyaddr((char *)&f->sin_addr,
- sizeof(struct in_addr), f->sin_family, result, res_len);
+ ret_len = priv_getnameinfo(f, result, res_len);
sigprocmask(SIG_SETMASK, &omask, NULL);
if (ret_len == 0) {
@@ -1154,6 +1236,9 @@ init(void)
(void)close(f->f_file);
break;
case F_FORW:
+ f->f_un.f_forw.f_num_addrs = 0;
+ free(f->f_un.f_forw.f_addrs);
+ f->f_un.f_forw.f_addrs = NULL;
break;
case F_MEMBUF:
ringbuf_free(f->f_un.f_mb.f_rb);
@@ -1242,7 +1327,8 @@ init(void)
break;
case F_FORW:
- printf("%s", f->f_un.f_forw.f_hname);
+ printf("%s:%s", f->f_un.f_forw.f_host,
+ f->f_un.f_forw.f_serv);
break;
case F_USERS:
@@ -1305,7 +1391,7 @@ find_dup(struct filed *f)
struct filed *
cfline(char *line, char *prog)
{
- int i, pri, addr_len;
+ int i, pri;
size_t rb_len;
char *bp, *p, *q, *cp;
char buf[MAXLINE], ebuf[100];
@@ -1399,32 +1485,77 @@ cfline(char *line, char *prog)
}
/* skip to action part */
- while (*p == '\t')
+ while (*p == '\t' || *p == ' ')
p++;
switch (*p) {
case '@':
- if (!InetInuse)
- break;
- if ((cp = strrchr(++p, ':')) != NULL)
+ if (!InetInuse) {
+ free(f);
+ return (NULL);
+ }
+ p++;
+ if (*p == '[') {
+ p++;
+ if ((cp = strchr(p, ']')) == NULL) {
+ bad_forward_addr:
+ snprintf(ebuf, sizeof(ebuf), "invalid "
+ "host/port specification \"%s\"", p);
+ logerror(ebuf);
+ free(f);
+ return (NULL);
+ }
*cp++ = '\0';
- if ((strlcpy(f->f_un.f_forw.f_hname, p,
- sizeof(f->f_un.f_forw.f_hname)) >=
- sizeof(f->f_un.f_forw.f_hname))) {
- snprintf(ebuf, sizeof(ebuf), "hostname too long \"%s\"",
- p);
+ if (*cp == ':')
+ cp++;
+ else if (*cp == '\0')
+ cp = NULL;
+ else
+ goto bad_forward_addr;
+ } else {
+ /* Don't allow IPv6 host:port without square braces */
+ if ((cp = strchr(p, ':')) != strrchr(p, ':'))
+ goto bad_forward_addr;
+ if (cp != NULL)
+ *cp++ = '\0';
+ }
+ /* Now 'p' points to hostname and 'cp' points to port or NULL */
+ if (cp == NULL)
+ cp = "syslog";
+
+ if (strlcpy(f->f_un.f_forw.f_host, p,
+ sizeof(f->f_un.f_forw.f_host)) >=
+ sizeof(f->f_un.f_forw.f_host)) {
+ snprintf(ebuf, sizeof(ebuf), "hostname name too "
+ "long \"%s\"", p);
+ logerror(ebuf);
+ break;
+ }
+ if (strlcpy(f->f_un.f_forw.f_serv, cp,
+ sizeof(f->f_un.f_forw.f_serv)) >=
+ sizeof(f->f_un.f_forw.f_serv)) {
+ snprintf(ebuf, sizeof(ebuf), "service name too "
+ "long \"%s\"", p);
logerror(ebuf);
break;
}
- addr_len = priv_gethostserv(f->f_un.f_forw.f_hname,
- cp == NULL ? "syslog" : cp,
- (struct sockaddr*)&f->f_un.f_forw.f_addr,
- sizeof(f->f_un.f_forw.f_addr));
- if (addr_len < 1) {
- snprintf(ebuf, sizeof(ebuf), "bad hostname \"%s\"", p);
+
+ f->f_un.f_forw.f_num_addrs = priv_getaddrinfo(
+ f->f_un.f_forw.f_host, f->f_un.f_forw.f_serv,
+ (struct sockaddr **)&f->f_un.f_forw.f_addrs);
+ f->f_un.f_forw.f_good_addr = 0;
+
+ if (f->f_un.f_forw.f_num_addrs <= 0) {
+ f->f_type = F_UNUSED;
+ f->f_un.f_forw.f_num_addrs = 0;
+ f->f_un.f_forw.f_addrs = NULL;
+ snprintf(ebuf, sizeof(ebuf), "bad host/service "
+ "name \"%s:%s\"", f->f_un.f_forw.f_host,
+ f->f_un.f_forw.f_serv);
logerror(ebuf);
break;
}
+
f->f_type = F_FORW;
break;
Index: syslogd.h
===================================================================
RCS file: /cvs/src/usr.sbin/syslogd/syslogd.h,v
retrieving revision 1.5
diff -u -p -r1.5 syslogd.h
--- syslogd.h 6 Jun 2005 23:22:04 -0000 1.5
+++ syslogd.h 6 Aug 2005 19:02:58 -0000
@@ -25,8 +25,8 @@ FILE *priv_open_utmp(void);
FILE *priv_open_config(void);
void priv_config_parse_done(void);
int priv_config_modified(void);
-int priv_gethostserv(char *, char *, struct sockaddr *, size_t);
-int priv_gethostbyaddr(char *, int, int, char *, size_t);
+int priv_getaddrinfo(char *, char *, struct sockaddr **);
+int priv_getnameinfo(struct sockaddr *, char *, size_t);
/* Terminal message */
char *ttymsg(struct iovec *, int, char *, int);
@@ -37,7 +37,14 @@ int receive_fd(int);
/* The list of domain sockets */
#define MAXFUNIX 21
+/* Maximum # of udp listening sockets */
+#define MAX_AI_PASSIVE 8
+/* Maximum # of addresses for loghost */
+#define MAX_GETADDR 128
+
extern int nfunix;
+extern int nfinet;
+extern int start_inetfds;
extern char *funixn[MAXFUNIX];
extern char *ctlsock_path;
@@ -45,13 +52,16 @@ extern char *ctlsock_path;
extern int Debug;
extern int Startup;
+/* inet-socket address family */
+extern int af;
+
/* fds to poll */
#define PFD_KLOG 0 /* Offset of /dev/klog entry */
-#define PFD_INET 1 /* Offset of inet socket entry */
-#define PFD_CTLSOCK 2 /* Offset of control socket entry */
-#define PFD_CTLCONN 3 /* Offset of control connection entry */
-#define PFD_UNIX_0 4 /* Start of Unix socket entries */
-#define N_PFD (PFD_UNIX_0 + MAXFUNIX) /* # of pollfd entries */
+#define PFD_CTLSOCK 1 /* Offset of control socket entry */
+#define PFD_CTLCONN 2 /* Offset of control connection entry */
+#define PFD_UNIX_0 3 /* Start of Unix socket entries */
+#define N_PFD (PFD_UNIX_0 + MAXFUNIX + MAX_AI_PASSIVE) /* # of pollfd
+ entries */
extern struct pollfd pfd[N_PFD];
struct ringbuf {
----- End forwarded message -----