This can also be used to send RST segments (if rst is true) and also
if correct seq and ack numbers are provided.
*/
-int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
+int ctdb_sys_send_tcp(int s,
+ const struct sockaddr_in *dest,
const struct sockaddr_in *src,
uint32_t seq, uint32_t ack, int rst)
{
- int s, ret;
- uint32_t one = 1;
+ int ret;
struct {
struct iphdr ip;
struct tcphdr tcp;
return -1;
}
- s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
- if (s == -1) {
- DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
- strerror(errno)));
- return -1;
- }
-
- ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
- if (ret != 0) {
- DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
- strerror(errno)));
- close(s);
- return -1;
- }
-
ZERO_STRUCT(pkt);
pkt.ip.version = 4;
pkt.ip.ihl = sizeof(pkt.ip)/4;
ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
if (ret != sizeof(pkt)) {
DEBUG(0,(__location__ " failed sendto (%s)\n", strerror(errno)));
- close(s);
return -1;
}
- close(s);
return 0;
}
return ret == 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.
+/* This function is used to open a raw socket to capture from
*/
-int ctdb_sys_kill_tcp(struct event_context *ev,
- const struct sockaddr_in *dst,
- const struct sockaddr_in *src)
+int ctdb_sys_open_capture_socket(void)
{
- 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;
+ int s;
/* Open a socket to capture all traffic */
s=socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
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 < sizeof(*eth)+sizeof(*ip)) {
- continue;
- }
-
- /* Ethernet */
- eth = (struct ether_header *)pkt;
- /* We only want IP packets */
- if (ntohs(eth->ether_type) != ETHERTYPE_IP) {
- continue;
- }
-
- /* IP */
- ip = (struct iphdr *)(eth+1);
- /* 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;
- }
-
- /* make sure its not a short packet */
- if (offsetof(struct tcphdr, ack_seq) + 4 +
- (ip->ihl*4) + sizeof(*eth) > ret) {
- continue;
- }
-
- /* TCP */
- tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
-
- /* 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"));
+ set_nonblocking(s);
+ set_close_on_exec(s);
- return -1;
+ return s;
}
-
-
-/* This function is used to open a raw socket to capture from
+/* This function is used to open a raw socket to send tickles from
*/
-int ctdb_sys_open_capture_socket(void)
+int ctdb_sys_open_sending_socket(void)
{
- int s;
+ int s, ret;
+ uint32_t one = 1;
- /* 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"));
+ s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+ if (s == -1) {
+ DEBUG(0,(__location__ " failed to open raw socket (%s)\n",
+ strerror(errno)));
+ return -1;
+ }
+
+ ret = setsockopt(s, SOL_IP, IP_HDRINCL, &one, sizeof(one));
+ if (ret != 0) {
+ DEBUG(0,(__location__ " failed to setup IP headers (%s)\n",
+ strerror(errno)));
+ close(s);
return -1;
}
+ set_nonblocking(s);
+ set_close_on_exec(s);
+
return s;
}
+
int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp)
{
int ret;
/* This one has been tickled !
now reset him and remove him from the list.
*/
- ctdb_sys_send_tcp(&conn->dst, &conn->src, tcp->ack_seq, tcp->seq, 1);
+ ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, &conn->src, tcp->ack_seq, tcp->seq, 1);
talloc_free(conn);
return 0;
/* from takeover/system.c */
int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface);
bool ctdb_sys_have_ip(const char *ip);
-int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
+int ctdb_sys_send_tcp(int fd,
+ 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);
struct ctdb_kill_tcp {
struct ctdb_context *ctdb;
int capture_fd;
+ int sending_fd;
struct fd_event *fde;
struct ctdb_killtcp_connection *connections;
};
int ctdb_sys_open_capture_socket(void);
+int ctdb_sys_open_sending_socket(void);
int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, struct sockaddr_in *src, struct sockaddr_in *dst);
int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp);
{
struct ctdb_takeover_arp *arp = talloc_get_type(private_data,
struct ctdb_takeover_arp);
- int ret;
+ int s, ret;
struct ctdb_tcp_list *tcp;
ret = ctdb_sys_send_arp(&arp->sin, arp->ctdb->takeover.interface);
DEBUG(0,(__location__ " sending of arp failed (%s)\n", strerror(errno)));
}
+ s = ctdb_sys_open_sending_socket();
+ if (s == -1) {
+ DEBUG(0,(__location__ " failed to open raw socket for sending tickles\n"));
+ return;
+ }
+
for (tcp=arp->tcp_list;tcp;tcp=tcp->next) {
DEBUG(2,("sending tcp tickle ack for %u->%s:%u\n",
(unsigned)ntohs(tcp->daddr.sin_port),
inet_ntoa(tcp->saddr.sin_addr),
(unsigned)ntohs(tcp->saddr.sin_port)));
- ret = ctdb_sys_send_tcp(&tcp->saddr, &tcp->daddr, 0, 0, 0);
+ ret = ctdb_sys_send_tcp(s, &tcp->saddr, &tcp->daddr, 0, 0, 0);
if (ret != 0) {
DEBUG(0,(__location__ " Failed to send tcp tickle ack for %s\n",
inet_ntoa(tcp->saddr.sin_addr)));
}
}
+ close(s);
arp->count++;
if (arp->count == CTDB_ARP_REPEAT) {
talloc_free(arp);
return;
}
-
+
event_add_timed(arp->ctdb->ev, arp->ctdb->takeover.last_ctx,
timeval_current_ofs(CTDB_ARP_INTERVAL, 0),
ctdb_control_send_arp, arp);
continue;
}
- ctdb_sys_send_tcp(&conn->dst, &conn->src, 0, 0, 0);
+ ctdb_sys_send_tcp(killtcp->sending_fd, &conn->dst, &conn->src, 0, 0, 0);
}
/* If there are no more connections to kill we can remove the
*/
static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
{
- close(killtcp->capture_fd);
- killtcp->capture_fd = -1;
+ if (killtcp->capture_fd != -1) {
+ close(killtcp->capture_fd);
+ killtcp->capture_fd = -1;
+ }
+ if (killtcp->sending_fd != -1) {
+ close(killtcp->sending_fd);
+ killtcp->sending_fd = -1;
+ }
killtcp->ctdb->killtcp = NULL;
return 0;
killtcp->ctdb = ctdb;
killtcp->capture_fd = -1;
+ killtcp->sending_fd = -1;
killtcp->connections = NULL;
ctdb->killtcp = killtcp;
talloc_set_destructor(killtcp, ctdb_killtcp_destructor);
DEBUG(0,(__location__ " Failed to open capturing socket for killtcp\n"));
goto failed;
}
-
- set_nonblocking(killtcp->capture_fd);
- set_close_on_exec(killtcp->capture_fd);
}
+ /* If we dont have a socket to send from yet we must create it
+ */
+ if (killtcp->sending_fd == -1) {
+ killtcp->sending_fd = ctdb_sys_open_sending_socket();
+ if (killtcp->sending_fd == -1) {
+ DEBUG(0,(__location__ " Failed to open sending socket for killtcp\n"));
+ goto failed;
+ }
+ }
conn = talloc(killtcp, struct ctdb_killtcp_connection);
CTDB_NO_MEMORY(ctdb, conn);