This enhances the framework for sending tcp tickles to be able to send ipv6 tickles as well.
Since we can not use one single RAW socket to send both handcrafted ipv4 and ipv6 packets, instead of always opening TWO sockets, one ipv4 and one ipv6 we get rid of the helper ctdb_sys_open_sending_socket() and just open (and close) a raw socket of the appropriate type inside ctdb_sys_send_tcp().
We know which type of socket v4/v6 to use based on the sin_family of the destination address.
Since ctdb_sys_send_tcp() opens its own socket we no longer nede to pass a socket
descriptor as a parameter. Get rid of this redundant parameter and fixup all callers.
}
+static bool parse_ipv4(const char *s, unsigned port, ctdb_sock_addr *saddr)
+{
+ saddr->ip.sin_family = AF_INET;
+ saddr->ip.sin_port = htons(port);
+
+ if (inet_pton(AF_INET, s, &saddr->ip.sin_addr) != 1) {
+ DEBUG(DEBUG_ERR, (__location__ " Failed to translate %s into sin_addr\n", s));
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_ipv6(const char *s, unsigned port, ctdb_sock_addr *saddr)
+{
+ saddr->ip6.sin6_family = AF_INET6;
+ saddr->ip6.sin6_port = htons(port);
+ saddr->ip6.sin6_flowinfo = 0;
+ saddr->ip6.sin6_scope_id = 0;
+
+ if (inet_pton(AF_INET6, s, &saddr->ip6.sin6_addr) != 1) {
+ DEBUG(DEBUG_ERR, (__location__ " Failed to translate %s into sin6_addr\n", s));
+ return false;
+ }
+
+ return true;
+}
/*
parse a ip:port pair
*/
-bool parse_ip_port(const char *s, struct sockaddr_in *ip)
+bool parse_ip_port(const char *addr, ctdb_sock_addr *saddr)
{
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ char *s, *p;
unsigned port;
- if (!parse_ip_num(s, &ip->sin_addr, &port, ':')) {
+ char *endp = NULL;
+ bool ret;
+
+ s = talloc_strdup(tmp_ctx, addr);
+ if (s == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " Failed strdup()\n"));
+ talloc_free(tmp_ctx);
return false;
}
- ip->sin_family = AF_INET;
- ip->sin_port = htons(port);
- return true;
+
+ p = rindex(s, ':');
+ if (p == NULL) {
+ DEBUG(DEBUG_ERR, (__location__ " This addr: %s does not contain a port number\n", s));
+ talloc_free(tmp_ctx);
+ return false;
+ }
+
+ port = strtoul(p+1, &endp, 10);
+ if (endp == NULL || *endp != 0) {
+ /* trailing garbage */
+ DEBUG(DEBUG_ERR, (__location__ " Trailing garbage after the port in %s\n", s));
+ talloc_free(tmp_ctx);
+ return false;
+ }
+ *p = 0;
+
+
+ /* now is this a ipv4 or ipv6 address ?*/
+ p = index(s, ':');
+ if (p == NULL) {
+ ret = parse_ipv4(s, port, saddr);
+ } else {
+ ret = parse_ipv6(s, port, saddr);
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
}
/*
+#if 0
+This function is no longer used and its code should be moved into
+send tcp packet after that function has been enhanced to do ipv6 as well.
/* This function is used to open a raw socket to send tickles from
*/
return s;
}
-
+#endif
/*
uint16 checksum for n bytes
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(int s,
- const struct sockaddr_in *dest,
- const struct sockaddr_in *src,
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
+ const ctdb_sock_addr *src,
uint32_t seq, uint32_t ack, int rst)
{
+ int s;
int ret;
+ uint32_t one = 1;
+ uint16_t tmpport;
+ ctdb_sock_addr *tmpdest;
struct {
struct iphdr ip;
struct tcphdr tcp;
- } pkt;
-
- /* for now, we only handle AF_INET addresses */
- if (src->sin_family != AF_INET || dest->sin_family != AF_INET) {
- DEBUG(DEBUG_CRIT,(__location__ " not an ipv4 address\n"));
- return -1;
- }
+ } ip4pkt;
+ struct {
+ struct ip6_hdr ip6;
+ struct tcphdr tcp;
+ } ip6pkt;
+
+ switch (src->ip.sin_family) {
+ case AF_INET:
+ ZERO_STRUCT(ip4pkt);
+ ip4pkt.ip.version = 4;
+ ip4pkt.ip.ihl = sizeof(ip4pkt.ip)/4;
+ ip4pkt.ip.tot_len = htons(sizeof(ip4pkt));
+ ip4pkt.ip.ttl = 255;
+ ip4pkt.ip.protocol = IPPROTO_TCP;
+ ip4pkt.ip.saddr = src->ip.sin_addr.s_addr;
+ ip4pkt.ip.daddr = dest->ip.sin_addr.s_addr;
+ ip4pkt.ip.check = 0;
+
+ ip4pkt.tcp.source = src->ip.sin_port;
+ ip4pkt.tcp.dest = dest->ip.sin_port;
+ ip4pkt.tcp.seq = seq;
+ ip4pkt.tcp.ack_seq = ack;
+ ip4pkt.tcp.ack = 1;
+ if (rst) {
+ ip4pkt.tcp.rst = 1;
+ }
+ ip4pkt.tcp.doff = sizeof(ip4pkt.tcp)/4;
+ /* this makes it easier to spot in a sniffer */
+ ip4pkt.tcp.window = htons(1234);
+ ip4pkt.tcp.check = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip);
+
+ /* open a raw socket to send this segment from */
+ s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW));
+ if (s == -1) {
+ DEBUG(DEBUG_CRIT,(__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(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
+ strerror(errno)));
+ close(s);
+ return -1;
+ }
+
+ set_nonblocking(s);
+ set_close_on_exec(s);
+
+ ret = sendto(s, &ip4pkt, sizeof(ip4pkt), 0, &dest->ip, sizeof(dest->ip));
+ close(s);
+ if (ret != sizeof(ip4pkt)) {
+ DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+ return -1;
+ }
+ break;
+ case AF_INET6:
+ ZERO_STRUCT(ip6pkt);
+ ip6pkt.ip6.ip6_vfc = 0x60;
+ ip6pkt.ip6.ip6_plen = 20;
+ ip6pkt.ip6.ip6_nxt = IPPROTO_TCP;
+ ip6pkt.ip6.ip6_hlim = 64;
+ ip6pkt.ip6.ip6_src = src->ip6.sin6_addr;
+ ip6pkt.ip6.ip6_dst = dest->ip6.sin6_addr;
+
+ ip6pkt.tcp.source = src->ip6.sin6_port;
+ ip6pkt.tcp.dest = dest->ip6.sin6_port;
+ ip6pkt.tcp.seq = seq;
+ ip6pkt.tcp.ack_seq = ack;
+ ip6pkt.tcp.ack = 1;
+ if (rst) {
+ ip6pkt.tcp.rst = 1;
+ }
+ ip6pkt.tcp.doff = sizeof(ip6pkt.tcp)/4;
+ /* this makes it easier to spot in a sniffer */
+ ip6pkt.tcp.window = htons(1234);
+ ip6pkt.tcp.check = tcp_checksum6((uint16_t *)&ip6pkt.tcp, sizeof(ip6pkt.tcp), &ip6pkt.ip6);
+
+ s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
+ if (s == -1) {
+ DEBUG(DEBUG_CRIT, (__location__ " Failed to open sending socket\n"));
+ return -1;
+
+ }
+ /* sendto() dont like if the port is set and the socket is
+ in raw mode.
+ */
+ tmpdest = discard_const(dest);
+ tmpport = tmpdest->ip6.sin6_port;
+
+ tmpdest->ip6.sin6_port = 0;
+ ret = sendto(s, &ip6pkt, sizeof(ip6pkt), 0, &dest->ip6, sizeof(dest->ip6));
+ tmpdest->ip6.sin6_port = tmpport;
+ close(s);
- ZERO_STRUCT(pkt);
- pkt.ip.version = 4;
- pkt.ip.ihl = sizeof(pkt.ip)/4;
- pkt.ip.tot_len = htons(sizeof(pkt));
- pkt.ip.ttl = 255;
- pkt.ip.protocol = IPPROTO_TCP;
- pkt.ip.saddr = src->sin_addr.s_addr;
- pkt.ip.daddr = dest->sin_addr.s_addr;
- pkt.ip.check = 0;
-
- pkt.tcp.source = src->sin_port;
- pkt.tcp.dest = dest->sin_port;
- pkt.tcp.seq = seq;
- pkt.tcp.ack_seq = ack;
- pkt.tcp.ack = 1;
- if (rst) {
- pkt.tcp.rst = 1;
- }
- pkt.tcp.doff = sizeof(pkt.tcp)/4;
- pkt.tcp.window = htons(1234); /* this makes it easier to spot in a sniffer */
- pkt.tcp.check = tcp_checksum((uint16_t *)&pkt.tcp, sizeof(pkt.tcp), &pkt.ip);
+ if (ret != sizeof(ip6pkt)) {
+ DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+ return -1;
+ }
+ break;
- ret = sendto(s, &pkt, sizeof(pkt), 0, dest, sizeof(*dest));
- if (ret != sizeof(pkt)) {
- DEBUG(DEBUG_CRIT,(__location__ " failed sendto (%s)\n", strerror(errno)));
+ default:
+ DEBUG(DEBUG_CRIT,(__location__ " not an ipv4/v6 address\n"));
return -1;
}
return 0;
}
-/*
- 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(DEBUG_CRIT,(__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(DEBUG_CRIT,(__location__ " failed to setup IP headers (%s)\n",
- strerror(errno)));
- close(s);
- return -1;
- }
-
- set_nonblocking(s);
- set_close_on_exec(s);
-
- return s;
-}
/*
called when the raw socket becomes readable
/* from takeover/system.c */
int ctdb_sys_send_arp(const struct sockaddr_in *saddr, const char *iface);
bool ctdb_sys_have_ip(struct sockaddr_in ip);
-int ctdb_sys_send_tcp(int fd,
- const struct sockaddr_in *dest,
- const struct sockaddr_in *src,
+int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
+ const ctdb_sock_addr *src,
uint32_t seq, uint32_t ack, int rst);
int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
void ctdb_start_freeze(struct ctdb_context *ctdb);
-bool parse_ip_port(const char *s, struct sockaddr_in *ip);
+bool parse_ip_port(const char *s, ctdb_sock_addr *saddr);
int ctdb_sys_open_capture_socket(const char *iface, void **private_data);
int ctdb_sys_close_capture_socket(void *private_data);
-int ctdb_sys_open_sending_socket(void);
int ctdb_sys_read_tcp_packet(int s, void *private_data, struct sockaddr_in *src, struct sockaddr_in *dst,
uint32_t *ack_seq, uint32_t *seq);
{
struct ctdb_takeover_arp *arp = talloc_get_type(private_data,
struct ctdb_takeover_arp);
- int i, s, ret;
+ int i, ret;
struct ctdb_tcp_array *tcparray;
DEBUG(DEBUG_CRIT,(__location__ " sending of arp failed (%s)\n", strerror(errno)));
}
- s = ctdb_sys_open_sending_socket();
- if (s == -1) {
- DEBUG(DEBUG_CRIT,(__location__ " failed to open raw socket for sending tickles\n"));
- return;
- }
-
tcparray = arp->tcparray;
if (tcparray) {
for (i=0;i<tcparray->num;i++) {
(unsigned)ntohs(tcparray->connections[i].daddr.sin_port),
inet_ntoa(tcparray->connections[i].saddr.sin_addr),
(unsigned)ntohs(tcparray->connections[i].saddr.sin_port)));
- ret = ctdb_sys_send_tcp(s, &tcparray->connections[i].saddr,
- &tcparray->connections[i].daddr, 0, 0, 0);
+ ret = ctdb_sys_send_tcp(
+ (ctdb_sock_addr *)&tcparray->connections[i].saddr,
+ (ctdb_sock_addr *)&tcparray->connections[i].daddr,
+ 0, 0, 0);
if (ret != 0) {
DEBUG(DEBUG_CRIT,(__location__ " Failed to send tcp tickle ack for %s\n",
inet_ntoa(tcparray->connections[i].saddr.sin_addr)));
}
}
- close(s);
arp->count++;
if (arp->count == CTDB_ARP_REPEAT) {
struct ctdb_vnn *vnn;
struct ctdb_context *ctdb;
int capture_fd;
- int sending_fd;
struct fd_event *fde;
trbt_tree_t *connections;
void *private_data;
*/
DEBUG(DEBUG_INFO, ("sending a tcp reset to kill connection :%d -> %s:%d\n", ntohs(con->dst.sin_port), inet_ntoa(con->src.sin_addr), ntohs(con->src.sin_port)));
- ctdb_sys_send_tcp(killtcp->sending_fd, &con->dst,
- &con->src, ack_seq, seq, 1);
+ ctdb_sys_send_tcp(
+ (ctdb_sock_addr *)&con->dst,
+ (ctdb_sock_addr *)&con->src,
+ ack_seq, seq, 1);
talloc_free(con);
}
static void tickle_connection_traverse(void *param, void *data)
{
struct ctdb_killtcp_con *con = talloc_get_type(data, struct ctdb_killtcp_con);
- struct ctdb_kill_tcp *killtcp = talloc_get_type(param, struct ctdb_kill_tcp);
/* have tried too many times, just give up */
if (con->count >= 5) {
/* othervise, try tickling it again */
con->count++;
- ctdb_sys_send_tcp(killtcp->sending_fd, &con->dst, &con->src, 0, 0, 0);
+ ctdb_sys_send_tcp(
+ (ctdb_sock_addr *)&con->dst,
+ (ctdb_sock_addr *)&con->src,
+ 0, 0, 0);
}
/* loop over all connections sending tickle ACKs */
- trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, killtcp);
+ trbt_traversearray32(killtcp->connections, KILLTCP_KEYLEN, tickle_connection_traverse, NULL);
/* If there are no more connections to kill we can remove the
*/
static int ctdb_killtcp_destructor(struct ctdb_kill_tcp *killtcp)
{
- if (killtcp->sending_fd != -1) {
- close(killtcp->sending_fd);
- killtcp->sending_fd = -1;
- }
killtcp->vnn->killtcp = NULL;
return 0;
}
killtcp->vnn = vnn;
killtcp->ctdb = ctdb;
killtcp->capture_fd = -1;
- killtcp->sending_fd = -1;
killtcp->connections = trbt_create(killtcp, 0);
vnn->killtcp = killtcp;
KILLTCP_KEYLEN, killtcp_key(&con->dst, &con->src),
add_killtcp_callback, con);
- /*
- 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(DEBUG_CRIT,(__location__ " Failed to open sending socket for killtcp\n"));
- goto failed;
- }
- }
-
/*
If we dont have a socket to listen on yet we must create it
*/
}
/* tickle him once now */
- ctdb_sys_send_tcp(killtcp->sending_fd, &con->dst, &con->src, 0, 0, 0);
+ ctdb_sys_send_tcp(
+ (ctdb_sock_addr *)&con->dst,
+ (ctdb_sock_addr *)&con->src,
+ 0, 0, 0);
return 0;
usage();
}
- if (!parse_ip_port(argv[0], &killtcp.src)) {
+ if (!parse_ip_port(argv[0], (ctdb_sock_addr *)&killtcp.src)) {
DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[0]));
return -1;
}
- if (!parse_ip_port(argv[1], &killtcp.dst)) {
+ if (!parse_ip_port(argv[1], (ctdb_sock_addr *)&killtcp.dst)) {
DEBUG(DEBUG_ERR, ("Bad IP:port '%s'\n", argv[1]));
return -1;
}
*/
static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
{
- int s, ret;
- struct sockaddr_in src, dst;
+ int ret;
+ ctdb_sock_addr src, dst;
if (argc < 2) {
usage();
return -1;
}
- s = ctdb_sys_open_sending_socket();
- if (s == -1) {
- DEBUG(DEBUG_ERR, ("Failed to open socket for sending tickle\n"));
- return 0;
- }
-
- ret = ctdb_sys_send_tcp(s, &src, &dst, 0, 0, 0);
- close(s);
+ ret = ctdb_sys_send_tcp(&src, &dst, 0, 0, 0);
if (ret==0) {
return 0;
}