CVE-2019-14907 lib/util: Do not print the failed to convert string into the logs
[Samba.git] / ctdb / tcp / tcp_connect.c
blobf54086fcd3c38786a1cb28a3a0ce42ea1aae98af
1 /*
2 ctdb over TCP
4 Copyright (C) Andrew Tridgell 2006
5 Copyright (C) Ronnie Sahlberg 2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "replace.h"
22 #include "system/network.h"
23 #include "system/filesys.h"
25 #include <talloc.h>
26 #include <tevent.h>
28 #include "lib/util/debug.h"
29 #include "lib/util/time.h"
30 #include "lib/util/blocking.h"
32 #include "ctdb_private.h"
34 #include "common/system.h"
35 #include "common/common.h"
36 #include "common/logging.h"
38 #include "ctdb_tcp.h"
41 stop any connecting (established or pending) to a node
43 void ctdb_tcp_stop_connection(struct ctdb_node *node)
45 struct ctdb_tcp_node *tnode = talloc_get_type(
46 node->transport_data, struct ctdb_tcp_node);
48 TALLOC_FREE(tnode->out_queue);
49 TALLOC_FREE(tnode->connect_te);
50 TALLOC_FREE(tnode->connect_fde);
51 if (tnode->out_fd != -1) {
52 close(tnode->out_fd);
53 tnode->out_fd = -1;
59 called when a complete packet has come in - should not happen on this socket
60 unless the other side closes the connection with RST or FIN
62 void ctdb_tcp_tnode_cb(uint8_t *data, size_t cnt, void *private_data)
64 struct ctdb_node *node = talloc_get_type(private_data, struct ctdb_node);
65 struct ctdb_tcp_node *tnode = talloc_get_type(
66 node->transport_data, struct ctdb_tcp_node);
68 if (data == NULL) {
69 node->ctdb->upcalls->node_dead(node);
72 ctdb_tcp_stop_connection(node);
73 tnode->connect_te = tevent_add_timer(node->ctdb->ev, tnode,
74 timeval_current_ofs(3, 0),
75 ctdb_tcp_node_connect, node);
76 TALLOC_FREE(data);
80 called when socket becomes writeable on connect
82 static void ctdb_node_connect_write(struct tevent_context *ev,
83 struct tevent_fd *fde,
84 uint16_t flags, void *private_data)
86 struct ctdb_node *node = talloc_get_type(private_data,
87 struct ctdb_node);
88 struct ctdb_tcp_node *tnode = talloc_get_type(node->transport_data,
89 struct ctdb_tcp_node);
90 struct ctdb_context *ctdb = node->ctdb;
91 int error = 0;
92 socklen_t len = sizeof(error);
93 int one = 1;
94 int ret;
96 TALLOC_FREE(tnode->connect_te);
98 ret = getsockopt(tnode->out_fd, SOL_SOCKET, SO_ERROR, &error, &len);
99 if (ret != 0 || error != 0) {
100 ctdb_tcp_stop_connection(node);
101 tnode->connect_te = tevent_add_timer(ctdb->ev, tnode,
102 timeval_current_ofs(1, 0),
103 ctdb_tcp_node_connect, node);
104 return;
107 TALLOC_FREE(tnode->connect_fde);
109 ret = setsockopt(tnode->out_fd,
110 IPPROTO_TCP,
111 TCP_NODELAY,
112 (char *)&one,
113 sizeof(one));
114 if (ret == -1) {
115 DBG_WARNING("Failed to set TCP_NODELAY on fd - %s\n",
116 strerror(errno));
118 ret = setsockopt(tnode->out_fd,
119 SOL_SOCKET,
120 SO_KEEPALIVE,(char *)&one,
121 sizeof(one));
122 if (ret == -1) {
123 DBG_WARNING("Failed to set KEEPALIVE on fd - %s\n",
124 strerror(errno));
127 tnode->out_queue = ctdb_queue_setup(node->ctdb,
128 tnode,
129 tnode->out_fd,
130 CTDB_TCP_ALIGNMENT,
131 ctdb_tcp_tnode_cb,
132 node,
133 "to-node-%s",
134 node->name);
135 if (tnode->out_queue == NULL) {
136 DBG_ERR("Failed to set up outgoing queue\n");
137 ctdb_tcp_stop_connection(node);
138 tnode->connect_te = tevent_add_timer(ctdb->ev,
139 tnode,
140 timeval_current_ofs(1, 0),
141 ctdb_tcp_node_connect,
142 node);
143 return;
146 /* the queue subsystem now owns this fd */
147 tnode->out_fd = -1;
150 * Mark the node to which this connection has been established
151 * as connected, but only if the corresponding listening
152 * socket is also connected
154 if (tnode->in_queue != NULL) {
155 node->ctdb->upcalls->node_connected(node);
161 called when we should try and establish a tcp connection to a node
163 void ctdb_tcp_node_connect(struct tevent_context *ev, struct tevent_timer *te,
164 struct timeval t, void *private_data)
166 struct ctdb_node *node = talloc_get_type(private_data,
167 struct ctdb_node);
168 struct ctdb_tcp_node *tnode = talloc_get_type(node->transport_data,
169 struct ctdb_tcp_node);
170 struct ctdb_context *ctdb = node->ctdb;
171 ctdb_sock_addr sock_in;
172 int sockin_size;
173 int sockout_size;
174 ctdb_sock_addr sock_out;
175 int ret;
177 ctdb_tcp_stop_connection(node);
179 sock_out = node->address;
181 tnode->out_fd = socket(sock_out.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
182 if (tnode->out_fd == -1) {
183 DBG_ERR("Failed to create socket\n");
184 return;
187 ret = set_blocking(tnode->out_fd, false);
188 if (ret != 0) {
189 DBG_ERR("Failed to set socket non-blocking (%s)\n",
190 strerror(errno));
191 close(tnode->out_fd);
192 tnode->out_fd = -1;
193 return;
196 set_close_on_exec(tnode->out_fd);
198 DBG_DEBUG("Created TCP SOCKET FD:%d\n", tnode->out_fd);
200 /* Bind our side of the socketpair to the same address we use to listen
201 * on incoming CTDB traffic.
202 * We must specify this address to make sure that the address we expose to
203 * the remote side is actually routable in case CTDB traffic will run on
204 * a dedicated non-routeable network.
206 sock_in = *ctdb->address;
208 /* AIX libs check to see if the socket address and length
209 arguments are consistent with each other on calls like
210 connect(). Can not get by with just sizeof(sock_in),
211 need sizeof(sock_in.ip).
213 switch (sock_in.sa.sa_family) {
214 case AF_INET:
215 sock_in.ip.sin_port = 0 /* Any port */;
216 sockin_size = sizeof(sock_in.ip);
217 sockout_size = sizeof(sock_out.ip);
218 break;
219 case AF_INET6:
220 sock_in.ip6.sin6_port = 0 /* Any port */;
221 sockin_size = sizeof(sock_in.ip6);
222 sockout_size = sizeof(sock_out.ip6);
223 break;
224 default:
225 DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
226 sock_in.sa.sa_family));
227 close(tnode->out_fd);
228 tnode->out_fd = -1;
229 return;
232 ret = bind(tnode->out_fd, (struct sockaddr *)&sock_in, sockin_size);
233 if (ret == -1) {
234 DBG_ERR("Failed to bind socket (%s)\n", strerror(errno));
235 close(tnode->out_fd);
236 tnode->out_fd = -1;
237 return;
240 ret = connect(tnode->out_fd,
241 (struct sockaddr *)&sock_out,
242 sockout_size);
243 if (ret != 0 && errno != EINPROGRESS) {
244 ctdb_tcp_stop_connection(node);
245 tnode->connect_te = tevent_add_timer(ctdb->ev,
246 tnode,
247 timeval_current_ofs(1, 0),
248 ctdb_tcp_node_connect,
249 node);
250 return;
253 /* non-blocking connect - wait for write event */
254 tnode->connect_fde = tevent_add_fd(node->ctdb->ev,
255 tnode,
256 tnode->out_fd,
257 TEVENT_FD_WRITE|TEVENT_FD_READ,
258 ctdb_node_connect_write,
259 node);
261 /* don't give it long to connect - retry in one second. This ensures
262 that we find a node is up quickly (tcp normally backs off a syn reply
263 delay by quite a lot) */
264 tnode->connect_te = tevent_add_timer(ctdb->ev,
265 tnode,
266 timeval_current_ofs(1, 0),
267 ctdb_tcp_node_connect,
268 node);
272 called when we get contacted by another node
273 currently makes no attempt to check if the connection is really from a ctdb
274 node in our cluster
276 static void ctdb_listen_event(struct tevent_context *ev, struct tevent_fd *fde,
277 uint16_t flags, void *private_data)
279 struct ctdb_context *ctdb = talloc_get_type(private_data, struct ctdb_context);
280 struct ctdb_tcp *ctcp = talloc_get_type(ctdb->transport_data,
281 struct ctdb_tcp);
282 ctdb_sock_addr addr;
283 socklen_t len;
284 int fd;
285 struct ctdb_node *node;
286 struct ctdb_tcp_node *tnode;
287 int one = 1;
288 int ret;
290 memset(&addr, 0, sizeof(addr));
291 len = sizeof(addr);
292 fd = accept(ctcp->listen_fd, (struct sockaddr *)&addr, &len);
293 if (fd == -1) return;
294 smb_set_close_on_exec(fd);
296 node = ctdb_ip_to_node(ctdb, &addr);
297 if (node == NULL) {
298 D_ERR("Refused connection from unknown node %s\n",
299 ctdb_addr_to_str(&addr));
300 close(fd);
301 return;
304 tnode = talloc_get_type_abort(node->transport_data,
305 struct ctdb_tcp_node);
306 if (tnode == NULL) {
307 /* This can't happen - see ctdb_tcp_initialise() */
308 DBG_ERR("INTERNAL ERROR setting up connection from node %s\n",
309 ctdb_addr_to_str(&addr));
310 close(fd);
311 return;
314 if (tnode->in_queue != NULL) {
315 DBG_ERR("Incoming queue active, rejecting connection from %s\n",
316 ctdb_addr_to_str(&addr));
317 close(fd);
318 return;
321 ret = set_blocking(fd, false);
322 if (ret != 0) {
323 DBG_ERR("Failed to set socket non-blocking (%s)\n",
324 strerror(errno));
325 close(fd);
326 return;
329 set_close_on_exec(fd);
331 DBG_DEBUG("Created SOCKET FD:%d to incoming ctdb connection\n", fd);
333 ret = setsockopt(fd,
334 SOL_SOCKET,
335 SO_KEEPALIVE,
336 (char *)&one,
337 sizeof(one));
338 if (ret == -1) {
339 DBG_WARNING("Failed to set KEEPALIVE on fd - %s\n",
340 strerror(errno));
343 tnode->in_queue = ctdb_queue_setup(ctdb,
344 tnode,
346 CTDB_TCP_ALIGNMENT,
347 ctdb_tcp_read_cb,
348 node,
349 "ctdbd-%s",
350 ctdb_addr_to_str(&addr));
351 if (tnode->in_queue == NULL) {
352 DBG_ERR("Failed to set up incoming queue\n");
353 close(fd);
354 return;
358 * Mark the connecting node as connected, but only if the
359 * corresponding outbound connected is also up
361 if (tnode->out_queue != NULL) {
362 node->ctdb->upcalls->node_connected(node);
368 automatically find which address to listen on
370 static int ctdb_tcp_listen_automatic(struct ctdb_context *ctdb)
372 struct ctdb_tcp *ctcp = talloc_get_type(ctdb->transport_data,
373 struct ctdb_tcp);
374 ctdb_sock_addr sock;
375 int lock_fd;
376 unsigned int i;
377 const char *lock_path = CTDB_RUNDIR "/.socket_lock";
378 struct flock lock;
379 int one = 1;
380 int sock_size;
381 struct tevent_fd *fde;
383 /* If there are no nodes, then it won't be possible to find
384 * the first one. Log a failure and short circuit the whole
385 * process.
387 if (ctdb->num_nodes == 0) {
388 DEBUG(DEBUG_CRIT,("No nodes available to attempt bind to - is the nodes file empty?\n"));
389 return -1;
392 /* in order to ensure that we don't get two nodes with the
393 same adddress, we must make the bind() and listen() calls
394 atomic. The SO_REUSEADDR setsockopt only prevents double
395 binds if the first socket is in LISTEN state */
396 lock_fd = open(lock_path, O_RDWR|O_CREAT, 0666);
397 if (lock_fd == -1) {
398 DEBUG(DEBUG_CRIT,("Unable to open %s\n", lock_path));
399 return -1;
402 lock.l_type = F_WRLCK;
403 lock.l_whence = SEEK_SET;
404 lock.l_start = 0;
405 lock.l_len = 1;
406 lock.l_pid = 0;
408 if (fcntl(lock_fd, F_SETLKW, &lock) != 0) {
409 DEBUG(DEBUG_CRIT,("Unable to lock %s\n", lock_path));
410 close(lock_fd);
411 return -1;
414 for (i=0; i < ctdb->num_nodes; i++) {
415 if (ctdb->nodes[i]->flags & NODE_FLAGS_DELETED) {
416 continue;
418 sock = ctdb->nodes[i]->address;
420 switch (sock.sa.sa_family) {
421 case AF_INET:
422 sock_size = sizeof(sock.ip);
423 break;
424 case AF_INET6:
425 sock_size = sizeof(sock.ip6);
426 break;
427 default:
428 DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
429 sock.sa.sa_family));
430 continue;
433 ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
434 if (ctcp->listen_fd == -1) {
435 ctdb_set_error(ctdb, "socket failed\n");
436 continue;
439 set_close_on_exec(ctcp->listen_fd);
441 if (setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,
442 (char *)&one,sizeof(one)) == -1) {
443 DEBUG(DEBUG_WARNING, ("Failed to set REUSEADDR on fd - %s\n",
444 strerror(errno)));
447 if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) == 0) {
448 break;
451 if (errno == EADDRNOTAVAIL) {
452 DEBUG(DEBUG_DEBUG,(__location__ " Failed to bind() to socket. %s(%d)\n",
453 strerror(errno), errno));
454 } else {
455 DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n",
456 strerror(errno), errno));
459 close(ctcp->listen_fd);
460 ctcp->listen_fd = -1;
463 if (i == ctdb->num_nodes) {
464 DEBUG(DEBUG_CRIT,("Unable to bind to any of the node addresses - giving up\n"));
465 goto failed;
467 ctdb->address = talloc_memdup(ctdb,
468 &ctdb->nodes[i]->address,
469 sizeof(ctdb_sock_addr));
470 if (ctdb->address == NULL) {
471 ctdb_set_error(ctdb, "Out of memory at %s:%d",
472 __FILE__, __LINE__);
473 goto failed;
476 ctdb->name = talloc_asprintf(ctdb, "%s:%u",
477 ctdb_addr_to_str(ctdb->address),
478 ctdb_addr_to_port(ctdb->address));
479 if (ctdb->name == NULL) {
480 ctdb_set_error(ctdb, "Out of memory at %s:%d",
481 __FILE__, __LINE__);
482 goto failed;
484 DEBUG(DEBUG_INFO,("ctdb chose network address %s\n", ctdb->name));
486 if (listen(ctcp->listen_fd, 10) == -1) {
487 goto failed;
490 fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
491 ctdb_listen_event, ctdb);
492 tevent_fd_set_auto_close(fde);
494 close(lock_fd);
496 return 0;
498 failed:
499 close(lock_fd);
500 if (ctcp->listen_fd != -1) {
501 close(ctcp->listen_fd);
502 ctcp->listen_fd = -1;
504 return -1;
509 listen on our own address
511 int ctdb_tcp_listen(struct ctdb_context *ctdb)
513 struct ctdb_tcp *ctcp = talloc_get_type(ctdb->transport_data,
514 struct ctdb_tcp);
515 ctdb_sock_addr sock;
516 int sock_size;
517 int one = 1;
518 struct tevent_fd *fde;
520 /* we can either auto-bind to the first available address, or we can
521 use a specified address */
522 if (!ctdb->address) {
523 return ctdb_tcp_listen_automatic(ctdb);
526 sock = *ctdb->address;
528 switch (sock.sa.sa_family) {
529 case AF_INET:
530 sock_size = sizeof(sock.ip);
531 break;
532 case AF_INET6:
533 sock_size = sizeof(sock.ip6);
534 break;
535 default:
536 DEBUG(DEBUG_ERR, (__location__ " unknown family %u\n",
537 sock.sa.sa_family));
538 goto failed;
541 ctcp->listen_fd = socket(sock.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
542 if (ctcp->listen_fd == -1) {
543 ctdb_set_error(ctdb, "socket failed\n");
544 return -1;
547 set_close_on_exec(ctcp->listen_fd);
549 if (setsockopt(ctcp->listen_fd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)) == -1) {
550 DEBUG(DEBUG_WARNING, ("Failed to set REUSEADDR on fd - %s\n",
551 strerror(errno)));
554 if (bind(ctcp->listen_fd, (struct sockaddr * )&sock, sock_size) != 0) {
555 DEBUG(DEBUG_ERR,(__location__ " Failed to bind() to socket. %s(%d)\n", strerror(errno), errno));
556 goto failed;
559 if (listen(ctcp->listen_fd, 10) == -1) {
560 goto failed;
563 fde = tevent_add_fd(ctdb->ev, ctcp, ctcp->listen_fd, TEVENT_FD_READ,
564 ctdb_listen_event, ctdb);
565 tevent_fd_set_auto_close(fde);
567 return 0;
569 failed:
570 if (ctcp->listen_fd != -1) {
571 close(ctcp->listen_fd);
573 ctcp->listen_fd = -1;
574 return -1;