ctdb_killtcp.c is now the only place it is needed.
Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
+++ /dev/null
-/*
- CTDB TCP connection killing code
-
- Copyright (C) Ronnie Sahlberg 2007
- Copyright (C) Andrew Tridgell 2007
- Copyright (C) Martin Schwenke 2016
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/network.h"
-
-#include "lib/util/debug.h"
-
-#include "protocol/protocol.h"
-#include "protocol/protocol_api.h"
-
-#include "common/rb_tree.h"
-#include "common/system.h"
-#include "common/logging.h"
-
-#include "killtcp.h"
-
-/* TCP connection to be killed */
-struct ctdb_killtcp_con {
- ctdb_sock_addr src_addr;
- ctdb_sock_addr dst_addr;
- int count;
- struct ctdb_kill_tcp *killtcp;
-};
-
-/* this function is used to create a key to represent this socketpair
- in the killtcp tree.
- this key is used to insert and lookup matching socketpairs that are
- to be tickled and RST
-*/
-#define KILLTCP_KEYLEN 10
-static uint32_t *killtcp_key(ctdb_sock_addr *src, ctdb_sock_addr *dst)
-{
- static uint32_t key[KILLTCP_KEYLEN];
-
- bzero(key, sizeof(key));
-
- if (src->sa.sa_family != dst->sa.sa_family) {
- DEBUG(DEBUG_ERR, (__location__ " ERROR, different families passed :%u vs %u\n", src->sa.sa_family, dst->sa.sa_family));
- return key;
- }
-
- switch (src->sa.sa_family) {
- case AF_INET:
- key[0] = dst->ip.sin_addr.s_addr;
- key[1] = src->ip.sin_addr.s_addr;
- key[2] = dst->ip.sin_port;
- key[3] = src->ip.sin_port;
- break;
- case AF_INET6: {
- uint32_t *dst6_addr32 =
- (uint32_t *)&(dst->ip6.sin6_addr.s6_addr);
- uint32_t *src6_addr32 =
- (uint32_t *)&(src->ip6.sin6_addr.s6_addr);
- key[0] = dst6_addr32[3];
- key[1] = src6_addr32[3];
- key[2] = dst6_addr32[2];
- key[3] = src6_addr32[2];
- key[4] = dst6_addr32[1];
- key[5] = src6_addr32[1];
- key[6] = dst6_addr32[0];
- key[7] = src6_addr32[0];
- key[8] = dst->ip6.sin6_port;
- key[9] = src->ip6.sin6_port;
- break;
- }
- default:
- DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", src->sa.sa_family));
- return key;
- }
-
- return key;
-}
-
-/*
- called when we get a read event on the raw socket
- */
-static void capture_tcp_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags, void *private_data)
-{
- struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
- struct ctdb_killtcp_con *con;
- ctdb_sock_addr src, dst;
- uint32_t ack_seq, seq;
-
- if (!(flags & TEVENT_FD_READ)) {
- return;
- }
-
- if (ctdb_sys_read_tcp_packet(killtcp->capture_fd,
- killtcp->private_data,
- &src, &dst,
- &ack_seq, &seq) != 0) {
- /* probably a non-tcp ACK packet */
- return;
- }
-
- /* check if we have this guy in our list of connections
- to kill
- */
- con = trbt_lookuparray32(killtcp->connections,
- KILLTCP_KEYLEN, killtcp_key(&src, &dst));
- if (con == NULL) {
- /* no this was some other packet we can just ignore */
- return;
- }
-
- /* This one has been tickled !
- now reset him and remove him from the list.
- */
- DEBUG(DEBUG_INFO,
- ("sending a tcp reset to kill connection :%d -> %s:%d\n",
- ntohs(con->dst_addr.ip.sin_port),
- ctdb_sock_addr_to_string(con, &con->src_addr),
- ntohs(con->src_addr.ip.sin_port)));
-
- ctdb_sys_send_tcp(&con->dst_addr, &con->src_addr, ack_seq, seq, 1);
- talloc_free(con);
-}
-
-
-/* when traversing the list of all tcp connections to send tickle acks to
- (so that we can capture the ack coming back and kill the connection
- by a RST)
- this callback is called for each connection we are currently trying to kill
-*/
-static int tickle_connection_traverse(void *param, void *data)
-{
- struct ctdb_killtcp_con *con = talloc_get_type(data, struct ctdb_killtcp_con);
-
- /* have tried too many times, just give up */
- if (con->count >= 5) {
- /* can't delete in traverse: reparent to delete_cons */
- talloc_steal(param, con);
- return 0;
- }
-
- /* othervise, try tickling it again */
- con->count++;
- ctdb_sys_send_tcp(
- (ctdb_sock_addr *)&con->dst_addr,
- (ctdb_sock_addr *)&con->src_addr,
- 0, 0, 0);
- return 0;
-}
-
-
-/*
- called every second until all sentenced connections have been reset
- */
-static void ctdb_tickle_sentenced_connections(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval t, void *private_data)
-{
- struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
- void *delete_cons = talloc_new(NULL);
-
- /* loop over all connections sending tickle ACKs */
- trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, delete_cons);
-
- /* now we've finished traverse, it's safe to do deletion. */
- talloc_free(delete_cons);
-
- /* If there are no more connections to kill we can remove the
- entire killtcp structure
- */
- if ((killtcp->connections == NULL) ||
- (killtcp->connections->root == NULL)) {
- talloc_free(killtcp);
- return;
- }
-
- /* try tickling them again in a seconds time
- */
- tevent_add_timer(ev, killtcp,
- tevent_timeval_current_ofs(1, 0),
- ctdb_tickle_sentenced_connections, killtcp);
-}
-
-/* nothing fancy here, just unconditionally replace any existing
- connection structure with the new one.
-
- don't even free the old one if it did exist, that one is talloc_stolen
- by the same node in the tree anyway and will be deleted when the new data
- is deleted
-*/
-static void *add_killtcp_callback(void *parm, void *data)
-{
- return parm;
-}
-
-/* Add a TCP socket to the list of connections we want to RST. The
- * list is attached to *killtcp_arg. If this is NULL then allocate
- * the structure. */
-int ctdb_killtcp(struct tevent_context *ev,
- TALLOC_CTX *mem_ctx,
- const char *iface,
- const ctdb_sock_addr *src,
- const ctdb_sock_addr *dst,
- struct ctdb_kill_tcp **killtcp_arg)
-{
- struct ctdb_kill_tcp *killtcp;
- struct ctdb_killtcp_con *con;
-
- if (killtcp_arg == NULL) {
- DEBUG(DEBUG_ERR, (__location__ " killtcp_arg is NULL!\n"));
- return -1;
- }
-
- killtcp = *killtcp_arg;
-
- /* Allocate a new structure if necessary. The structure is
- * only freed when mem_ctx is freed. */
- if (killtcp == NULL) {
- killtcp = talloc_zero(mem_ctx, struct ctdb_kill_tcp);
- if (killtcp == NULL) {
- DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
- return -1;
- }
-
- killtcp->capture_fd = -1;
- killtcp->connections = trbt_create(killtcp, 0);
- *killtcp_arg = killtcp;
- }
-
- /* create a structure that describes this connection we want to
- RST and store it in killtcp->connections
- */
- con = talloc(killtcp, struct ctdb_killtcp_con);
- if (con == NULL) {
- DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
- return -1;
- }
- con->src_addr = *src;
- con->dst_addr = *dst;
- con->count = 0;
- con->killtcp = killtcp;
-
-
- trbt_insertarray32_callback(killtcp->connections,
- KILLTCP_KEYLEN,
- killtcp_key(&con->dst_addr,
- &con->src_addr),
- add_killtcp_callback, con);
-
- /*
- If we don't have a socket to listen on yet we must create it
- */
- if (killtcp->capture_fd == -1) {
- killtcp->capture_fd =
- ctdb_sys_open_capture_socket(iface,
- &killtcp->private_data);
- if (killtcp->capture_fd == -1) {
- DEBUG(DEBUG_CRIT,(__location__ " Failed to open capturing "
- "socket on iface '%s' for killtcp (%s)\n",
- iface, strerror(errno)));
- return -1;
- }
- }
-
-
- if (killtcp->fde == NULL) {
- killtcp->fde = tevent_add_fd(ev, killtcp,
- killtcp->capture_fd,
- TEVENT_FD_READ,
- capture_tcp_handler, killtcp);
- tevent_fd_set_auto_close(killtcp->fde);
-
- /* We also need to set up some events to tickle all these connections
- until they are all reset
- */
- tevent_add_timer(ev, killtcp, tevent_timeval_current_ofs(1, 0),
- ctdb_tickle_sentenced_connections, killtcp);
- }
-
- /* tickle him once now */
- ctdb_sys_send_tcp(
- &con->dst_addr,
- &con->src_addr,
- 0, 0, 0);
-
- return 0;
-}
+++ /dev/null
-/*
- CTDB TCP connection killing code
-
- Copyright (C) Ronnie Sahlberg 2007
- Copyright (C) Andrew Tridgell 2007
- Copyright (C) Martin Schwenke 2016
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _CTDB_KILLTCP_H_
-#define _CTDB_KILLTCP_H_
-
-#include <talloc.h>
-#include <tevent.h>
-
-#include "replace.h"
-#include "system/network.h"
-
-#include "common/rb_tree.h"
-
-#include "protocol/protocol.h"
-
-/* Contains the listening socket and the list of TCP connections to
- * kill */
-struct ctdb_kill_tcp {
- int capture_fd;
- struct tevent_fd *fde;
- trbt_tree_t *connections;
- void *private_data;
- void *destructor_data;
-};
-
-
-/* Add a TCP socket to the list of connections we want to RST. The
- * list is attached to *killtcp_arg. If this is NULL then allocate
- * the structure. */
-int ctdb_killtcp(struct tevent_context *ev,
- TALLOC_CTX *mem_ctx,
- const char *iface,
- const ctdb_sock_addr *src,
- const ctdb_sock_addr *dst,
- struct ctdb_kill_tcp **killtcp_arg);
-
-#endif /* _CTDB_KILLTCP_H_ */
along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <talloc.h>
+#include <tevent.h>
+
#include "replace.h"
#include "system/network.h"
#include "lib/util/debug.h"
#include "protocol/protocol.h"
+#include "protocol/protocol_api.h"
+#include "common/rb_tree.h"
#include "common/system.h"
#include "common/logging.h"
-#include "server/killtcp.h"
+
+/* Contains the listening socket and the list of TCP connections to
+ * kill */
+struct ctdb_kill_tcp {
+ int capture_fd;
+ struct tevent_fd *fde;
+ trbt_tree_t *connections;
+ void *private_data;
+ void *destructor_data;
+};
static const char *prog;
+/* TCP connection to be killed */
+struct ctdb_killtcp_con {
+ ctdb_sock_addr src_addr;
+ ctdb_sock_addr dst_addr;
+ int count;
+ struct ctdb_kill_tcp *killtcp;
+};
+
+/* this function is used to create a key to represent this socketpair
+ in the killtcp tree.
+ this key is used to insert and lookup matching socketpairs that are
+ to be tickled and RST
+*/
+#define KILLTCP_KEYLEN 10
+static uint32_t *killtcp_key(ctdb_sock_addr *src, ctdb_sock_addr *dst)
+{
+ static uint32_t key[KILLTCP_KEYLEN];
+
+ bzero(key, sizeof(key));
+
+ if (src->sa.sa_family != dst->sa.sa_family) {
+ DEBUG(DEBUG_ERR, (__location__ " ERROR, different families passed :%u vs %u\n", src->sa.sa_family, dst->sa.sa_family));
+ return key;
+ }
+
+ switch (src->sa.sa_family) {
+ case AF_INET:
+ key[0] = dst->ip.sin_addr.s_addr;
+ key[1] = src->ip.sin_addr.s_addr;
+ key[2] = dst->ip.sin_port;
+ key[3] = src->ip.sin_port;
+ break;
+ case AF_INET6: {
+ uint32_t *dst6_addr32 =
+ (uint32_t *)&(dst->ip6.sin6_addr.s6_addr);
+ uint32_t *src6_addr32 =
+ (uint32_t *)&(src->ip6.sin6_addr.s6_addr);
+ key[0] = dst6_addr32[3];
+ key[1] = src6_addr32[3];
+ key[2] = dst6_addr32[2];
+ key[3] = src6_addr32[2];
+ key[4] = dst6_addr32[1];
+ key[5] = src6_addr32[1];
+ key[6] = dst6_addr32[0];
+ key[7] = src6_addr32[0];
+ key[8] = dst->ip6.sin6_port;
+ key[9] = src->ip6.sin6_port;
+ break;
+ }
+ default:
+ DEBUG(DEBUG_ERR, (__location__ " ERROR, unknown family passed :%u\n", src->sa.sa_family));
+ return key;
+ }
+
+ return key;
+}
+
+/*
+ called when we get a read event on the raw socket
+ */
+static void capture_tcp_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags, void *private_data)
+{
+ struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+ struct ctdb_killtcp_con *con;
+ ctdb_sock_addr src, dst;
+ uint32_t ack_seq, seq;
+
+ if (!(flags & TEVENT_FD_READ)) {
+ return;
+ }
+
+ if (ctdb_sys_read_tcp_packet(killtcp->capture_fd,
+ killtcp->private_data,
+ &src, &dst,
+ &ack_seq, &seq) != 0) {
+ /* probably a non-tcp ACK packet */
+ return;
+ }
+
+ /* check if we have this guy in our list of connections
+ to kill
+ */
+ con = trbt_lookuparray32(killtcp->connections,
+ KILLTCP_KEYLEN, killtcp_key(&src, &dst));
+ if (con == NULL) {
+ /* no this was some other packet we can just ignore */
+ return;
+ }
+
+ /* This one has been tickled !
+ now reset him and remove him from the list.
+ */
+ DEBUG(DEBUG_INFO,
+ ("sending a tcp reset to kill connection :%d -> %s:%d\n",
+ ntohs(con->dst_addr.ip.sin_port),
+ ctdb_sock_addr_to_string(con, &con->src_addr),
+ ntohs(con->src_addr.ip.sin_port)));
+
+ ctdb_sys_send_tcp(&con->dst_addr, &con->src_addr, ack_seq, seq, 1);
+ talloc_free(con);
+}
+
+
+/* when traversing the list of all tcp connections to send tickle acks to
+ (so that we can capture the ack coming back and kill the connection
+ by a RST)
+ this callback is called for each connection we are currently trying to kill
+*/
+static int tickle_connection_traverse(void *param, void *data)
+{
+ struct ctdb_killtcp_con *con = talloc_get_type(data, struct ctdb_killtcp_con);
+
+ /* have tried too many times, just give up */
+ if (con->count >= 5) {
+ /* can't delete in traverse: reparent to delete_cons */
+ talloc_steal(param, con);
+ return 0;
+ }
+
+ /* othervise, try tickling it again */
+ con->count++;
+ ctdb_sys_send_tcp(
+ (ctdb_sock_addr *)&con->dst_addr,
+ (ctdb_sock_addr *)&con->src_addr,
+ 0, 0, 0);
+ return 0;
+}
+
+
+/*
+ called every second until all sentenced connections have been reset
+ */
+static void ctdb_tickle_sentenced_connections(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval t, void *private_data)
+{
+ struct ctdb_kill_tcp *killtcp = talloc_get_type(private_data, struct ctdb_kill_tcp);
+ void *delete_cons = talloc_new(NULL);
+
+ /* loop over all connections sending tickle ACKs */
+ trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, delete_cons);
+
+ /* now we've finished traverse, it's safe to do deletion. */
+ talloc_free(delete_cons);
+
+ /* If there are no more connections to kill we can remove the
+ entire killtcp structure
+ */
+ if ((killtcp->connections == NULL) ||
+ (killtcp->connections->root == NULL)) {
+ talloc_free(killtcp);
+ return;
+ }
+
+ /* try tickling them again in a seconds time
+ */
+ tevent_add_timer(ev, killtcp,
+ tevent_timeval_current_ofs(1, 0),
+ ctdb_tickle_sentenced_connections, killtcp);
+}
+
+/* nothing fancy here, just unconditionally replace any existing
+ connection structure with the new one.
+
+ don't even free the old one if it did exist, that one is talloc_stolen
+ by the same node in the tree anyway and will be deleted when the new data
+ is deleted
+*/
+static void *add_killtcp_callback(void *parm, void *data)
+{
+ return parm;
+}
+
+/* Add a TCP socket to the list of connections we want to RST. The
+ * list is attached to *killtcp_arg. If this is NULL then allocate
+ * the structure. */
+static int ctdb_killtcp(struct tevent_context *ev,
+ TALLOC_CTX *mem_ctx,
+ const char *iface,
+ const ctdb_sock_addr *src,
+ const ctdb_sock_addr *dst,
+ struct ctdb_kill_tcp **killtcp_arg)
+{
+ struct ctdb_kill_tcp *killtcp;
+ struct ctdb_killtcp_con *con;
+
+ if (killtcp_arg == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " killtcp_arg is NULL!\n"));
+ return -1;
+ }
+
+ killtcp = *killtcp_arg;
+
+ /* Allocate a new structure if necessary. The structure is
+ * only freed when mem_ctx is freed. */
+ if (killtcp == NULL) {
+ killtcp = talloc_zero(mem_ctx, struct ctdb_kill_tcp);
+ if (killtcp == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+ return -1;
+ }
+
+ killtcp->capture_fd = -1;
+ killtcp->connections = trbt_create(killtcp, 0);
+ *killtcp_arg = killtcp;
+ }
+
+ /* create a structure that describes this connection we want to
+ RST and store it in killtcp->connections
+ */
+ con = talloc(killtcp, struct ctdb_killtcp_con);
+ if (con == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " out of memory\n"));
+ return -1;
+ }
+ con->src_addr = *src;
+ con->dst_addr = *dst;
+ con->count = 0;
+ con->killtcp = killtcp;
+
+
+ trbt_insertarray32_callback(killtcp->connections,
+ KILLTCP_KEYLEN,
+ killtcp_key(&con->dst_addr,
+ &con->src_addr),
+ add_killtcp_callback, con);
+
+ /*
+ If we don't have a socket to listen on yet we must create it
+ */
+ if (killtcp->capture_fd == -1) {
+ killtcp->capture_fd =
+ ctdb_sys_open_capture_socket(iface,
+ &killtcp->private_data);
+ if (killtcp->capture_fd == -1) {
+ DEBUG(DEBUG_CRIT,(__location__ " Failed to open capturing "
+ "socket on iface '%s' for killtcp (%s)\n",
+ iface, strerror(errno)));
+ return -1;
+ }
+ }
+
+
+ if (killtcp->fde == NULL) {
+ killtcp->fde = tevent_add_fd(ev, killtcp,
+ killtcp->capture_fd,
+ TEVENT_FD_READ,
+ capture_tcp_handler, killtcp);
+ tevent_fd_set_auto_close(killtcp->fde);
+
+ /* We also need to set up some events to tickle all these connections
+ until they are all reset
+ */
+ tevent_add_timer(ev, killtcp, tevent_timeval_current_ofs(1, 0),
+ ctdb_tickle_sentenced_connections, killtcp);
+ }
+
+ /* tickle him once now */
+ ctdb_sys_send_tcp(
+ &con->dst_addr,
+ &con->src_addr,
+ 0, 0, 0);
+
+ return 0;
+}
+
static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
{
bool *done = killtcp->destructor_data;
manpages='ctdb.1')
bld.SAMBA_BINARY('ctdb_killtcp',
- source='tools/ctdb_killtcp.c server/killtcp.c',
+ source='tools/ctdb_killtcp.c',
deps='''ctdb-protocol ctdb-util ctdb-system
samba-util replace''',
install_path='${CTDB_HELPER_BINDIR}')