Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F169301615
D57394.id179803.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D57394.id179803.diff
View Options
diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c
--- a/usr.sbin/syslogd/syslogd.c
+++ b/usr.sbin/syslogd/syslogd.c
@@ -1752,6 +1752,24 @@
}
#endif
+static int
+find_forw_fd(const struct sockaddr_storage *rss,
+ const struct sockaddr_storage *lss, struct filed *skip)
+{
+ struct filed *f;
+
+ STAILQ_FOREACH(f, &fhead, next) {
+ if (f->f_type != F_FORW || f == skip)
+ continue;
+ for (size_t i = 0; i < f->f_num_addr_fds; ++i) {
+ if (memcmp(&f->f_addrs[i].raddr, rss, rss->ss_len) == 0 &&
+ memcmp(&f->f_addrs[i].laddr, lss, lss->ss_len) == 0)
+ return (f->f_addr_fds[i]);
+ }
+ }
+ return (-1);
+}
+
static void
fprintlog_write(struct filed *f, struct iovlist *il, int flags)
{
@@ -1760,13 +1778,14 @@
ssize_t lsent;
if (Debug) {
- int domain, sockfd = f->f_addr_fds[0];
+ int domain, port, sockfd = f->f_addr_fds[0];
socklen_t len = sizeof(domain);
if (getsockopt(sockfd, SOL_SOCKET, SO_DOMAIN,
&domain, &len) < 0)
err(1, "getsockopt");
+ port = -1;
printf(" %s", f->f_hname);
switch (domain) {
#ifdef INET
@@ -1776,8 +1795,10 @@
len = sizeof(sin);
if (getpeername(sockfd,
(struct sockaddr *)&sin, &len) < 0)
- err(1, "getpeername");
- printf(":%d\n", ntohs(sin.sin_port));
+ warn("getpeername");
+ else
+ port = ntohs(sin.sin_port);
+ printf(":%d\n", port);
break;
}
#endif
@@ -1788,8 +1809,10 @@
len = sizeof(sin6);
if (getpeername(sockfd,
(struct sockaddr *)&sin6, &len) < 0)
- err(1, "getpeername");
- printf(":%d\n", ntohs(sin6.sin6_port));
+ warn("getpeername");
+ else
+ port = ntohs(sin6.sin6_port);
+ printf(":%d\n", port);
break;
}
#endif
@@ -1803,23 +1826,76 @@
iovlist_truncate(il, MaxForwardLen);
#endif
+ /*
+ * We have some constraints on message forwarding:
+ * - we want to send messages from an address to which syslogd
+ * is bound,
+ * - syslogd might start before the system's routes are
+ * configured, in which case connect() will fail,
+ * - there may be multiple logging rules which forward a message
+ * to a given address, i.e., sockets from different fileds
+ * may have the same <laddr, raddr> tuple,
+ * - we don't want to use casper to forward messages for us, as
+ * that's a lot of overhead to add to each message.
+ *
+ * These constraints plus Capsicum's restrictions make this
+ * rather complicated. We handle the first constraint by
+ * calling bind() when setting up forwarding sockets. The
+ * second constraint is handled by allowing connect() to fail
+ * during setup; if the sendmsg() call below fails for that
+ * reason, we then use cap_connect() to connect it lazily.
+ * Finally, that connect() call may fail due to the third
+ * constraint, in which case we look for another matching socket
+ * and use that one instead.
+ */
lsent = 0;
for (size_t i = 0; i < f->f_num_addr_fds; ++i) {
struct msghdr msg = {
.msg_iov = il->iov,
.msg_iovlen = il->iovcnt,
};
+ int fd;
- lsent = sendmsg(f->f_addr_fds[i], &msg, 0);
+ fd = f->f_addr_fds[i];
+ lsent = sendmsg(fd, &msg, 0);
+ if (lsent == -1 &&
+ (errno == ENOTCONN || errno == EDESTADDRREQ)) {
+ int error;
+
+ error = cap_connect(cap_net, fd,
+ (struct sockaddr *)&f->f_addrs[i].raddr,
+ f->f_addrs[i].raddr.ss_len);
+ if (error != 0 && errno == EADDRINUSE) {
+ fd = find_forw_fd(&f->f_addrs[i].raddr,
+ &f->f_addrs[i].laddr, f);
+ if (fd != -1) {
+ (void)dup2(fd,
+ f->f_addr_fds[i]);
+ fd = f->f_addr_fds[i];
+ } else {
+ /*
+ * Something is preventing us
+ * from connecting, we don't
+ * have much recourse. Keep
+ * fd==-1 to trigger an error
+ * from sendmsg() below.
+ */
+ dprintf(
+ "failed to connect to %s",
+ f->f_hname);
+ }
+ }
+ lsent = sendmsg(fd, &msg, 0);
+ }
if (lsent == (ssize_t)il->totalsize && !send_to_all)
break;
}
dprintf("lsent/totalsize: %zd/%zu\n", lsent, il->totalsize);
if (lsent != (ssize_t)il->totalsize) {
int e = errno;
+
logerror("sendto");
- errno = e;
- switch (errno) {
+ switch (e) {
case ENOBUFS:
case ENETDOWN:
case ENETUNREACH:
@@ -1828,6 +1904,9 @@
case EADDRNOTAVAIL:
case EAGAIN:
case ECONNREFUSED:
+ case ENOTCONN:
+ case EDESTADDRREQ:
+ case EADDRINUSE:
break;
/* case EBADF: */
/* case EACCES: */
@@ -1836,7 +1915,7 @@
/* case EMSGSIZE: */
default:
dprintf("removing entry: errno=%d\n", e);
- f->f_type = F_UNUSED;
+ close_filed(f);
break;
}
}
@@ -2533,7 +2612,7 @@
err(1, "Failed to open the system.net libcasper service");
cap_close(cap_casper);
limit = cap_net_limit_init(cap_net,
- CAPNET_ADDR2NAME | CAPNET_NAME2ADDR);
+ CAPNET_ADDR2NAME | CAPNET_NAME2ADDR | CAPNET_CONNECT);
if (limit == NULL)
err(1, "Failed to create system.net limits");
if (cap_net_limit(limit) == -1)
@@ -2641,15 +2720,18 @@
&domain, &len) < 0)
err(1, "getsockopt");
+ port = -1;
switch (domain) {
#ifdef INET
case AF_INET: {
struct sockaddr_in sin;
len = sizeof(sin);
- if (getpeername(sockfd, (struct sockaddr *)&sin, &len) < 0)
- err(1, "getpeername");
- port = ntohs(sin.sin_port);
+ if (getpeername(sockfd,
+ (struct sockaddr *)&sin, &len) < 0)
+ warn("getpeername");
+ else
+ port = ntohs(sin.sin_port);
break;
}
#endif
@@ -2658,20 +2740,18 @@
struct sockaddr_in6 sin6;
len = sizeof(sin6);
- if (getpeername(sockfd, (struct sockaddr *)&sin6, &len) < 0)
- err(1, "getpeername");
- port = ntohs(sin6.sin6_port);
+ if (getpeername(sockfd,
+ (struct sockaddr *)&sin6, &len) < 0)
+ warn("getpeername");
+ else
+ port = ntohs(sin6.sin6_port);
break;
}
#endif
default:
port = 0;
}
- if (port != 514) {
- printf("%s:%d", f->f_hname, port);
- } else {
- printf("%s", f->f_hname);
- }
+ printf("%s:%d", f->f_hname, port);
break;
}
@@ -3014,13 +3094,20 @@
errc(1, EADDRINUSE, "connect");
(void)close(s);
s = s1;
+ } else if (errno == ENETUNREACH || errno == EHOSTUNREACH) {
+ /*
+ * We can't connect right now, the system is probably
+ * not fully configured. We will try again, using
+ * cap_net, once something actually tries to log.
+ */
+ ;
} else {
err(1, "connect");
}
}
/* Make it a write-only socket. */
if (shutdown(s, SHUT_RD) < 0)
- err(1, "shutdown");
+ warn("shutdown");
return (s);
}
@@ -3144,7 +3231,8 @@
};
error = getaddrinfo(f->f_hname, p ? p : "syslog", &hints, &res);
if (error) {
- dprintf("%s\n", gai_strerror(error));
+ dprintf("getaddrinfo(%s): %s\n", f->f_hname,
+ gai_strerror(error));
break;
}
make_forw_socket_array(nvl, f, res);
diff --git a/usr.sbin/syslogd/syslogd_cap_config.c b/usr.sbin/syslogd/syslogd_cap_config.c
--- a/usr.sbin/syslogd/syslogd_cap_config.c
+++ b/usr.sbin/syslogd/syslogd_cap_config.c
@@ -226,6 +226,13 @@
if (filed->f_addr_fds[i] < 0)
err(1, "dup");
}
+ filed->f_addrs = calloc(filed->f_num_addr_fds,
+ sizeof(*filed->f_addrs));
+ if (filed->f_addrs == NULL)
+ err(1, "calloc");
+ memcpy(filed->f_addrs,
+ nvlist_get_binary(nvl_filed, "f_addrs", NULL),
+ filed->f_num_addr_fds * sizeof(*filed->f_addrs));
} else if (filed->f_type == F_PIPE) {
(void)strlcpy(filed->f_pname, nvlist_get_string(nvl_filed,
"f_pname"), sizeof(filed->f_pname));
diff --git a/usr.sbin/syslogd/tests/Makefile b/usr.sbin/syslogd/tests/Makefile
--- a/usr.sbin/syslogd/tests/Makefile
+++ b/usr.sbin/syslogd/tests/Makefile
@@ -7,8 +7,7 @@
# Run in jail with new vnet so we don't need to worry about address conflicts
TEST_METADATA= execenv="jail" \
- execenv_jail_params="vnet=new" \
- timeout=20
+ execenv_jail_params="vnet=new"
${PACKAGE}FILES=syslogd_format_test_common.sh \
syslogd_test_common.sh
diff --git a/usr.sbin/syslogd/tests/syslogd_test.sh b/usr.sbin/syslogd/tests/syslogd_test.sh
--- a/usr.sbin/syslogd/tests/syslogd_test.sh
+++ b/usr.sbin/syslogd/tests/syslogd_test.sh
@@ -588,6 +588,74 @@
syslogd_cleanup
}
+atf_test_case "forward_reload" "cleanup"
+forward_reload_head()
+{
+ atf_set descr "syslogd might start before routes are configured"
+ atf_set require.user root
+}
+forward_reload_body()
+{
+ local epair server client
+
+ server=syslogd_server$$
+ client=syslogd_client$$
+
+ syslogd_check_req epair
+
+ atf_check -o save:epair ifconfig epair create
+ epair=$(cat epair)
+ epair=${epair%%a}
+
+ syslogd_mkjail $server vnet
+ atf_check ifconfig ${epair}a vnet $server
+ atf_check jexec $server ifconfig ${epair}a inet6 fd00::2/64
+
+ syslogd_mkjail $client vnet
+ atf_check ifconfig ${epair}b vnet $client
+
+ cat <<__EOF__ > ./server_config
+user.debug ${SYSLOGD_LOGFILE}
+ftp.debug ${SYSLOGD_LOGFILE}
+__EOF__
+
+ syslogd_start -j $server -f ${PWD}/server_config -b fd00::2
+
+ cat <<__EOF__ > ./client_config
+user.debug @[fd00::2]
+ftp.debug @[fd00::2]
+__EOF__
+
+ syslogd_start -j $client -f ${PWD}/client_config \
+ -p ${PWD}/client -P ${SYSLOGD_PIDFILE}.2
+
+ # Make sure the client can't reach the server with the current
+ # network configuration.
+ atf_check -s not-exit:0 -e match:"No route to host" \
+ jexec $client ping6 -c 1 fd00::2
+
+ syslogd_log_jail $client -p user.debug -t test1 "hello there"
+ syslogd_log_jail $client -p ftp.debug -t test2 "hi there"
+
+ atf_check jexec $client ifconfig ${epair}b inet6 fd00::1/64
+ atf_check -o ignore jexec $client ping6 -c 1 fd00::2
+
+ syslogd_check_log_nomatch "test1: hello there"
+ syslogd_check_log_nomatch "test2: hi there"
+
+ syslogd_log_jail $client \
+ -p user.debug -t test1 -h ${PWD}/client "how about now"
+ syslogd_check_log "test1: how about now"
+
+ syslogd_log_jail $client \
+ -p ftp.debug -t test2 -h ${PWD}/client "bing bong"
+ syslogd_check_log "test2: bing bong"
+}
+forward_reload_cleanup()
+{
+ syslogd_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "unix"
@@ -605,4 +673,5 @@
atf_add_test_case "allowed_peer_forwarding"
atf_add_test_case "allowed_peer_wildcard"
atf_add_test_case "forward"
+ atf_add_test_case "forward_reload"
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Sep 2, 3:59 AM (8 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37899011
Default Alt Text
D57394.id179803.diff (10 KB)
Attached To
Mode
D57394: syslogd: Handle connection errors when setting up forwarding sockets
Attached
Detach File
Event Timeline
Log In to Comment