mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
as an optimization for when we want to send multiple tickles at a time
let the caller create the sending socket and use a single socket instead of one new one for each tickle. pass a sending socket to ctdb_sys_send_tcp() ctdb_sys_kill_tcp is not longer used so remove it set the socketflags for close on exec and nonblocking in the helper that creates the sockets instead of in the caller add a helper to create a sending socket to send tickles from (This used to be ctdb commit 469f3fb238a0674a2b48fdf1a7e657e32428178a)
This commit is contained in:
parent
823b7d4a5f
commit
a650497680
@ -183,12 +183,12 @@ static uint16_t tcp_checksum(uint16_t *data, size_t n, struct iphdr *ip)
|
||||
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;
|
||||
@ -200,21 +200,6 @@ int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
|
||||
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;
|
||||
@ -240,11 +225,9 @@ int ctdb_sys_send_tcp(const struct sockaddr_in *dest,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -273,119 +256,6 @@ bool ctdb_sys_have_ip(const char *ip)
|
||||
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.
|
||||
*/
|
||||
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 < 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"));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This function is used to open a raw socket to capture from
|
||||
*/
|
||||
int ctdb_sys_open_capture_socket(void)
|
||||
@ -399,9 +269,41 @@ int ctdb_sys_open_capture_socket(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_nonblocking(s);
|
||||
set_close_on_exec(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* This function is used to open a raw socket to send tickles from
|
||||
*/
|
||||
int ctdb_sys_open_sending_socket(void)
|
||||
{
|
||||
int s, ret;
|
||||
uint32_t one = 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;
|
||||
}
|
||||
|
||||
set_nonblocking(s);
|
||||
set_close_on_exec(s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp)
|
||||
{
|
||||
int ret;
|
||||
@ -469,7 +371,7 @@ int ctdb_sys_read_tcp_packet(struct ctdb_kill_tcp *killtcp)
|
||||
/* 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;
|
||||
|
@ -990,12 +990,10 @@ int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
|
||||
/* 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);
|
||||
@ -1061,10 +1059,12 @@ struct ctdb_killtcp_connection {
|
||||
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);
|
||||
|
||||
|
@ -69,7 +69,7 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
|
||||
{
|
||||
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);
|
||||
@ -77,25 +77,32 @@ static void ctdb_control_send_arp(struct event_context *ev, struct timed_event *
|
||||
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);
|
||||
@ -869,7 +876,7 @@ static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct t
|
||||
|
||||
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
|
||||
@ -891,8 +898,14 @@ static void ctdb_tickle_sentenced_connections(struct event_context *ev, struct t
|
||||
*/
|
||||
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;
|
||||
@ -921,6 +934,7 @@ int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, struct sockaddr_in *s
|
||||
|
||||
killtcp->ctdb = ctdb;
|
||||
killtcp->capture_fd = -1;
|
||||
killtcp->sending_fd = -1;
|
||||
killtcp->connections = NULL;
|
||||
ctdb->killtcp = killtcp;
|
||||
talloc_set_destructor(killtcp, ctdb_killtcp_destructor);
|
||||
@ -934,11 +948,17 @@ int ctdb_killtcp_add_connection(struct ctdb_context *ctdb, struct sockaddr_in *s
|
||||
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);
|
||||
|
@ -338,7 +338,7 @@ static int kill_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
*/
|
||||
static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
int ret;
|
||||
int s, ret;
|
||||
struct sockaddr_in src, dst;
|
||||
|
||||
if (argc < 2) {
|
||||
@ -355,7 +355,14 @@ static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
|
||||
s = ctdb_sys_open_sending_socket();
|
||||
if (s == -1) {
|
||||
printf("Failed to open socket for sending tickle\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = ctdb_sys_send_tcp(s, &src, &dst, 0, 0, 0);
|
||||
close(s);
|
||||
if (ret==0) {
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user