]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
add a new ctdb_sys_kill_tcp() function that kills (RST) the specified
authorRonnie Sahlberg <sahlberg@ronnie>
Wed, 4 Jul 2007 03:53:22 +0000 (13:53 +1000)
committerRonnie Sahlberg <sahlberg@ronnie>
Wed, 4 Jul 2007 03:53:22 +0000 (13:53 +1000)
connection

(This used to be ctdb commit 11a972f37d4ca7daf052b3b502620af05699bec4)

ctdb/include/ctdb_private.h
ctdb/takeover/system.c

index 7f1c5e30c641023f14effc193b31ee4d8e846cd8..053a0fcf2a7468ceb6ab60d90fb52e5ad23db6f6 100644 (file)
@@ -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);
index 74a860a918e34206bb836040027cf1136c1baf2f..e6df9b779907ea4b12bf7a4bbaa1379257b2b2a3 100644 (file)
@@ -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;
+}