summaryrefslogtreecommitdiff
path: root/usr.sbin/nsd/server.c
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2013-09-03 09:27:00 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2013-09-03 09:27:00 +0000
commit9bca93eb8a6a42e42ff6e3c4dbf9ad981af9d565 (patch)
treeb125d8043dfb04fd420c5d07a067ea25a811ce3b /usr.sbin/nsd/server.c
parent3a46b2e4c37dd915f3a6f15fc551ecac02132dbe (diff)
merge NSD 3.2.16
Diffstat (limited to 'usr.sbin/nsd/server.c')
-rw-r--r--usr.sbin/nsd/server.c114
1 files changed, 92 insertions, 22 deletions
diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c
index 6ac7ee9b51c..650b1914844 100644
--- a/usr.sbin/nsd/server.c
+++ b/usr.sbin/nsd/server.c
@@ -174,6 +174,8 @@ static void handle_tcp_writing(netio_type *netio,
* Send all children the quit nonblocking, then close pipe.
*/
static void send_children_quit(struct nsd* nsd);
+/* same, for shutdown time, waits for child to exit to avoid restart issues */
+static void send_children_quit_and_wait(struct nsd* nsd);
/* set childrens flags to send NSD_STATS to them */
#ifdef BIND8_STATS
@@ -358,7 +360,7 @@ int
server_init(struct nsd *nsd)
{
size_t i;
-#if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU)))
+#if defined(SO_REUSEADDR) || (defined(INET6) && (defined(IPV6_V6ONLY) || defined(IPV6_USE_MIN_MTU) || defined(IPV6_MTU) || defined(IP_TRANSPARENT)))
int on = 1;
#endif
@@ -459,6 +461,15 @@ server_init(struct nsd *nsd)
}
/* Bind it... */
+ if (nsd->options->ip_transparent) {
+#ifdef IP_TRANSPARENT
+ if (setsockopt(nsd->udp[i].s, IPPROTO_IP, IP_TRANSPARENT, &on, sizeof(on)) < 0) {
+ log_msg(LOG_ERR, "setsockopt(...,IP_TRANSPARENT, ...) failed for udp: %s",
+ strerror(errno));
+ }
+#endif /* IP_TRANSPARENT */
+ }
+
if (bind(nsd->udp[i].s, (struct sockaddr *) nsd->udp[i].addr->ai_addr, nsd->udp[i].addr->ai_addrlen) != 0) {
log_msg(LOG_ERR, "can't bind udp socket: %s", strerror(errno));
return -1;
@@ -491,12 +502,39 @@ server_init(struct nsd *nsd)
}
#endif /* SO_REUSEADDR */
-#if defined(INET6) && defined(IPV6_V6ONLY)
- if (nsd->tcp[i].addr->ai_family == AF_INET6 &&
- setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
- {
- log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno));
- return -1;
+#if defined(INET6)
+ if (nsd->tcp[i].addr->ai_family == AF_INET6) {
+# if defined(IPV6_V6ONLY)
+ if (setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_V6ONLY,
+ &on, sizeof(on)) < 0) {
+ log_msg(LOG_ERR, "setsockopt(..., IPV6_V6ONLY, ...) failed: %s", strerror(errno));
+ return -1;
+ }
+# endif
+# if defined(IPV6_USE_MIN_MTU)
+ /*
+ * Use minimum MTU to minimize delays learning working
+ * PMTU when communicating through a tunnel.
+ */
+ if (setsockopt(nsd->tcp[i].s,
+ IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+ &on, sizeof(on)) < 0) {
+ log_msg(LOG_ERR, "setsockopt(..., IPV6_USE_MIN_MTU, ...) failed: %s", strerror(errno));
+ return -1;
+ }
+# elif defined(IPV6_MTU)
+ /*
+ * On Linux, PMTUD is disabled by default for datagrams
+ * so set the MTU equal to the MIN MTU to get the same.
+ */
+ on = IPV6_MIN_MTU;
+ if (setsockopt(nsd->tcp[i].s, IPPROTO_IPV6, IPV6_MTU,
+ &on, sizeof(on)) < 0) {
+ log_msg(LOG_ERR, "setsockopt(..., IPV6_MTU, ...) failed: %s", strerror(errno));
+ return -1;
+ }
+ on = 1;
+# endif
}
#endif
/* set it nonblocking */
@@ -507,6 +545,15 @@ server_init(struct nsd *nsd)
}
/* Bind it... */
+ if (nsd->options->ip_transparent) {
+#ifdef IP_TRANSPARENT
+ if (setsockopt(nsd->tcp[i].s, IPPROTO_IP, IP_TRANSPARENT, &on, sizeof(on)) < 0) {
+ log_msg(LOG_ERR, "setsockopt(...,IP_TRANSPARENT, ...) failed for tcp: %s",
+ strerror(errno));
+ }
+#endif /* IP_TRANSPARENT */
+ }
+
if (bind(nsd->tcp[i].s, (struct sockaddr *) nsd->tcp[i].addr->ai_addr, nsd->tcp[i].addr->ai_addrlen) != 0) {
log_msg(LOG_ERR, "can't bind tcp socket: %s", strerror(errno));
return -1;
@@ -543,7 +590,10 @@ server_prepare(struct nsd *nsd)
#endif
rrl_mmap_init(nsd->child_count, nsd->options->rrl_size,
nsd->options->rrl_ratelimit,
- nsd->options->rrl_whitelist_ratelimit);
+ nsd->options->rrl_whitelist_ratelimit,
+ nsd->options->rrl_slip,
+ nsd->options->rrl_ipv4_prefix_length,
+ nsd->options->rrl_ipv6_prefix_length);
#endif /* RATELIMIT */
/* Open the database... */
@@ -592,8 +642,8 @@ server_start_children(struct nsd *nsd, region_type* region, netio_type* netio,
return restart_child_servers(nsd, region, netio, xfrd_sock_p);
}
-static void
-close_all_sockets(struct nsd_socket sockets[], size_t n)
+void
+server_close_all_sockets(struct nsd_socket sockets[], size_t n)
{
size_t i;
@@ -617,8 +667,8 @@ server_shutdown(struct nsd *nsd)
{
size_t i;
- close_all_sockets(nsd->udp, nsd->ifs);
- close_all_sockets(nsd->tcp, nsd->ifs);
+ server_close_all_sockets(nsd->udp, nsd->ifs);
+ server_close_all_sockets(nsd->tcp, nsd->ifs);
/* CHILD: close command channel to parent */
if(nsd->this_child && nsd->this_child->parent_fd != -1)
{
@@ -806,7 +856,7 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio,
/* Start new child processes */
if (server_start_children(nsd, server_region, netio, xfrd_sock_p) != 0) {
- send_children_quit(nsd);
+ send_children_quit(nsd); /* no wait required */
exit(1);
}
@@ -815,7 +865,7 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio,
DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from main %d", cmd));
if(cmd == NSD_QUIT) {
DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: quit to follow nsd"));
- send_children_quit(nsd);
+ send_children_quit(nsd); /* no wait required */
exit(0);
}
}
@@ -850,7 +900,7 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio,
log_msg(LOG_ERR, "reload: could not wait for parent to quit: %s",
strerror(errno));
}
- DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc reply main %d %d", ret, cmd));
+ DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc reply main %d %d", ret, (int)cmd));
if(cmd == NSD_QUIT) {
/* small race condition possible here, parent got quit cmd. */
send_children_quit(nsd);
@@ -1009,7 +1059,7 @@ server_main(struct nsd *nsd)
/* Start the child processes that handle incoming queries */
if (server_start_children(nsd, server_region, netio, &xfrd_listener.fd) != 0) {
- send_children_quit(nsd);
+ send_children_quit(nsd); /* no wait required */
exit(1);
}
reload_listener.fd = -1;
@@ -1170,7 +1220,7 @@ server_main(struct nsd *nsd)
close(reload_listener.fd);
}
/* only quit children after xfrd has acked */
- send_children_quit(nsd);
+ send_children_quit(nsd); /* no wait required */
namedb_fd_close(nsd->db);
region_destroy(server_region);
@@ -1179,7 +1229,7 @@ server_main(struct nsd *nsd)
/* ENOTREACH */
break;
case NSD_SHUTDOWN:
- send_children_quit(nsd);
+ send_children_quit_and_wait(nsd);
log_msg(LOG_WARNING, "signal received, shutting down...");
break;
case NSD_REAP_CHILDREN:
@@ -1262,10 +1312,10 @@ server_child(struct nsd *nsd)
DEBUG(DEBUG_IPC, 2, (LOG_INFO, "child process started"));
if (!(nsd->server_kind & NSD_SERVER_TCP)) {
- close_all_sockets(nsd->tcp, nsd->ifs);
+ server_close_all_sockets(nsd->tcp, nsd->ifs);
}
if (!(nsd->server_kind & NSD_SERVER_UDP)) {
- close_all_sockets(nsd->udp, nsd->ifs);
+ server_close_all_sockets(nsd->udp, nsd->ifs);
}
if (nsd->this_child && nsd->this_child->parent_fd != -1) {
@@ -1348,8 +1398,11 @@ server_child(struct nsd *nsd)
/* Do we need to do the statistics... */
if (mode == NSD_STATS) {
#ifdef BIND8_STATS
+ int p = nsd->st.period;
+ nsd->st.period = 1; /* force stats printout */
/* Dump the statistics */
bind8_stats(nsd);
+ nsd->st.period = p;
#else /* !BIND8_STATS */
log_msg(LOG_NOTICE, "Statistics support not enabled at compile time.");
#endif /* BIND8_STATS */
@@ -2030,9 +2083,8 @@ handle_tcp_accept(netio_type *netio,
}
static void
-send_children_quit(struct nsd* nsd)
+send_children_command(struct nsd* nsd, sig_atomic_t command, int timeout)
{
- sig_atomic_t command = NSD_QUIT;
size_t i;
assert(nsd->server_kind == NSD_SERVER_MAIN && nsd->this_child == 0);
for (i = 0; i < nsd->child_count; ++i) {
@@ -2046,6 +2098,11 @@ send_children_quit(struct nsd* nsd)
(int) command,
(int) nsd->children[i].pid,
strerror(errno));
+ } else if (timeout > 0) {
+ /* wait for reply */
+ (void)block_read(NULL,
+ nsd->children[i].child_fd,
+ &command, sizeof(command), timeout);
}
fsync(nsd->children[i].child_fd);
close(nsd->children[i].child_fd);
@@ -2054,6 +2111,19 @@ send_children_quit(struct nsd* nsd)
}
}
+static void
+send_children_quit(struct nsd* nsd)
+{
+ send_children_command(nsd, NSD_QUIT, 0);
+}
+
+static void
+send_children_quit_and_wait(struct nsd* nsd)
+{
+ DEBUG(DEBUG_IPC, 1, (LOG_INFO, "send children quit and wait"));
+ send_children_command(nsd, NSD_QUIT_CHILD, 3);
+}
+
#ifdef BIND8_STATS
static void
set_children_stats(struct nsd* nsd)