From: Ronnie Sahlberg Date: Wed, 4 Jul 2007 03:53:22 +0000 (+1000) Subject: add a new ctdb_sys_kill_tcp() function that kills (RST) the specified X-Git-Tag: tevent-0.9.20~348^2~2477^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a52f6760f379ca299c5716d02ae7baf2ab935ac9;p=thirdparty%2Fsamba.git add a new ctdb_sys_kill_tcp() function that kills (RST) the specified connection (This used to be ctdb commit 11a972f37d4ca7daf052b3b502620af05699bec4) --- diff --git a/ctdb/include/ctdb_private.h b/ctdb/include/ctdb_private.h index 7f1c5e30c64..053a0fcf2a7 100644 --- a/ctdb/include/ctdb_private.h +++ b/ctdb/include/ctdb_private.h @@ -984,6 +984,9 @@ bool ctdb_sys_have_ip(const char *ip); int ctdb_sys_send_tcp(const struct sockaddr_in *dest, const struct sockaddr_in *src, uint32_t seq, uint32_t ack, int rst); +int ctdb_sys_kill_tcp(struct event_context *ev, + const struct sockaddr_in *dest, + const struct sockaddr_in *src); int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist); int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script); diff --git a/ctdb/takeover/system.c b/ctdb/takeover/system.c index 74a860a918e..e6df9b77990 100644 --- a/ctdb/takeover/system.c +++ b/ctdb/takeover/system.c @@ -438,3 +438,108 @@ int ctdb_event_script_callback(struct ctdb_context *ctdb, return 0; } + + +static void ctdb_wait_handler(struct event_context *ev, struct timed_event *te, + struct timeval yt, void *p) +{ + uint32_t *timed_out = (uint32_t *)p; + (*timed_out) = 1; +} + +/* This function is used to kill (RST) the specified tcp connection. + + This function is not asynchronous and will block until the operation + was successful or it timesout. + */ +int ctdb_sys_kill_tcp(struct event_context *ev, + const struct sockaddr_in *dst, + const struct sockaddr_in *src) +{ + int s, ret; + uint32_t timedout; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); +#define RCVPKTSIZE 100 + char pkt[RCVPKTSIZE]; + struct ether_header *eth; + struct iphdr *ip; + struct tcphdr *tcp; + + /* Open a socket to capture all traffic */ + s=socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (s == -1){ + DEBUG(0,(__location__ " failed to open raw socket\n")); + return -1; + } + + /* We wait for up to 1 second for the ACK coming back */ + timedout = 0; + event_add_timed(ev, tmp_ctx, timeval_current_ofs(1, 0), ctdb_wait_handler, &timedout); + + /* Send a tickle ack to probe what the real seq/ack numbers are */ + ctdb_sys_send_tcp(dst, src, 0, 0, 0); + + /* Wait until we either time out or we succeeds in sending the RST */ + while (timedout==0) { + event_loop_once(ev); + + ret = recv(s, pkt, RCVPKTSIZE, MSG_TRUNC); + if (ret<40) { + continue; + } + + /* Ethernet */ + eth = (struct ether_header *)pkt; + /* We only want IP packets */ + if (ntohs(eth->ether_type) != ETHERTYPE_IP) { + continue; + } + + /* IP */ + ip = (struct iphdr *)&pkt[14]; + /* We only want IPv4 packets */ + if (ip->version != 4) { + continue; + } + /* Dont look at fragments */ + if ((ntohs(ip->frag_off)&0x1fff) != 0) { + continue; + } + /* we only want TCP */ + if (ip->protocol != IPPROTO_TCP) { + continue; + } + + /* We only want packets sent from the guy we tickled */ + if (ip->saddr != dst->sin_addr.s_addr) { + continue; + } + /* We only want packets sent to us */ + if (ip->daddr != src->sin_addr.s_addr) { + continue; + } + + /* TCP */ + tcp = (struct tcphdr *)&pkt[14+ip->ihl*4]; + /* We only want replies from the port we tickled */ + if (tcp->source != dst->sin_port) { + continue; + } + if (tcp->dest != src->sin_port) { + continue; + } + + ctdb_sys_send_tcp(dst, src, tcp->ack_seq, tcp->seq, 1); + + close(s); + talloc_free(tmp_ctx); + + return 0; + } + + close(s); + talloc_free(tmp_ctx); + DEBUG(0,(__location__ " timedout waiting for tickle ack reply\n")); + + return -1; +}