11 #include <sys/param.h>
13 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <netinet/ip.h>
20 #include <netinet/tcp.h>
34 #ifdef HAVE_GNUTLS_GNUTLS_H
36 # include <gnutls/gnutls.h>
38 const int psk_tls_kx_order[] = {
43 const int anon_tls_kx_order[] = {
53 #ifdef HAVE_LINUX_SWAB_H
54 # include <linux/swab.h>
60 #define __swab16(x) ((uint16_t)( \
61 (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
62 (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
64 #define __swab32(x) ((uint32_t)( \
65 (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
66 (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
67 (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
68 (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
70 #define __swab64(x) ((uint64_t)( \
71 (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
72 (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
73 (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
74 (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
75 (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
76 (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
77 (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
78 (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56)))
81 #define REMOTE_MSG_VERSION 1
82 #define ENDIAN_LOCAL 0xBADADBBD
84 struct crm_remote_header_v0
99 static struct crm_remote_header_v0 *
102 struct crm_remote_header_v0 *header = (
struct crm_remote_header_v0 *)remote->
buffer;
103 if(remote->
buffer_offset <
sizeof(
struct crm_remote_header_v0)) {
111 crm_err(
"Invalid message detected, endian mismatch: %" X32T
112 " is neither %" X32T " nor the swab'd %" X32T,
118 header->flags =
__swab64(header->flags);
119 header->endian =
__swab32(header->endian);
121 header->version =
__swab32(header->version);
122 header->size_total =
__swab32(header->size_total);
123 header->payload_offset =
__swab32(header->payload_offset);
124 header->payload_compressed =
__swab32(header->payload_compressed);
125 header->payload_uncompressed =
__swab32(header->payload_uncompressed);
131 #ifdef HAVE_GNUTLS_GNUTLS_H
134 crm_initiate_client_tls_handshake(
crm_remote_t * remote,
int timeout_ms)
138 time_t start = time(NULL);
141 rc = gnutls_handshake(*remote->tls_session);
142 if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN) {
150 }
while (((time(NULL) - start) < (timeout_ms / 1000)) &&
151 (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN));
154 crm_trace(
"gnutls_handshake() failed with %d", rc);
168 const char *dh_min_bits_s = getenv(
"PCMK_dh_min_bits");
177 if (dh_min_bits > 0) {
178 crm_info(
"Requiring server use a Diffie-Hellman prime of at least %d bits",
180 gnutls_dh_set_prime_bits(*session, dh_min_bits);
186 pcmk__bound_dh_bits(
unsigned int dh_bits)
188 const char *dh_min_bits_s = getenv(
"PCMK_dh_min_bits");
189 const char *dh_max_bits_s = getenv(
"PCMK_dh_max_bits");
198 if ((dh_min_bits > 0) && (dh_max_bits > 0)
199 && (dh_max_bits < dh_min_bits)) {
200 crm_warn(
"Ignoring PCMK_dh_max_bits because it is less than PCMK_dh_min_bits");
204 if ((dh_min_bits > 0) && (dh_bits < dh_min_bits)) {
207 if ((dh_max_bits > 0) && (dh_bits > dh_max_bits)) {
225 pcmk__new_tls_session(
int csock,
unsigned int conn_type,
226 gnutls_credentials_type_t cred_type,
void *credentials)
228 int rc = GNUTLS_E_SUCCESS;
229 const char *prio_base = NULL;
240 prio_base = getenv(
"PCMK_tls_priorities");
241 if (prio_base == NULL) {
245 (cred_type == GNUTLS_CRD_ANON)?
"+ANON-DH" :
"+DHE-PSK:+PSK");
248 if (session == NULL) {
249 rc = GNUTLS_E_MEMORY_ERROR;
253 rc = gnutls_init(session, conn_type);
254 if (rc != GNUTLS_E_SUCCESS) {
262 rc = gnutls_priority_set_direct(*session, prio, NULL);
263 if (rc != GNUTLS_E_SUCCESS) {
266 if (conn_type == GNUTLS_CLIENT) {
267 pcmk__set_minimum_dh_bits(session);
270 gnutls_transport_set_ptr(*session,
271 (gnutls_transport_ptr_t) GINT_TO_POINTER(csock));
273 rc = gnutls_credentials_set(*session, cred_type, credentials);
274 if (rc != GNUTLS_E_SUCCESS) {
281 crm_err(
"Could not initialize %s TLS %s session: %s "
282 CRM_XS " rc=%d priority='%s'",
283 (cred_type == GNUTLS_CRD_ANON)?
"anonymous" :
"PSK",
284 (conn_type == GNUTLS_SERVER)?
"server" :
"client",
285 gnutls_strerror(rc), rc, prio);
287 if (session != NULL) {
288 gnutls_free(session);
309 pcmk__init_tls_dh(gnutls_dh_params_t *dh_params)
311 int rc = GNUTLS_E_SUCCESS;
312 unsigned int dh_bits = 0;
314 rc = gnutls_dh_params_init(dh_params);
315 if (rc != GNUTLS_E_SUCCESS) {
319 #ifdef HAVE_GNUTLS_SEC_PARAM_TO_PK_BITS
320 dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
321 GNUTLS_SEC_PARAM_NORMAL);
323 rc = GNUTLS_E_DH_PRIME_UNACCEPTABLE;
329 dh_bits = pcmk__bound_dh_bits(dh_bits);
331 crm_info(
"Generating Diffie-Hellman parameters with %u-bit prime for TLS",
333 rc = gnutls_dh_params_generate2(*dh_params, dh_bits);
334 if (rc != GNUTLS_E_SUCCESS) {
341 crm_err(
"Could not initialize Diffie-Hellman parameters for TLS: %s "
342 CRM_XS " rc=%d", gnutls_strerror(rc), rc);
367 rc = gnutls_handshake(*client->
remote->tls_session);
368 }
while (rc == GNUTLS_E_INTERRUPTED);
370 if (rc == GNUTLS_E_AGAIN) {
375 }
else if (rc != GNUTLS_E_SUCCESS) {
384 const char *unsent = buf;
393 crm_trace(
"Message size: %llu", (
unsigned long long) len);
396 rc = gnutls_record_send(*session, unsent, len);
398 if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN) {
400 (
unsigned long long) len);
405 gnutls_strerror(rc), rc);
409 }
else if (rc < len) {
410 crm_debug(
"Sent %d of %llu bytes", rc, (
unsigned long long) len);
419 return rc < 0 ? rc : total_send;
424 crm_send_plaintext(
int sock,
const char *buf,
size_t len)
428 const char *unsent = buf;
436 crm_trace(
"Message on socket %d: size=%llu",
437 sock, (
unsigned long long) len);
439 rc = write(sock, unsent, len);
449 "Could only write %d of the remaining %llu bytes",
450 rc, (
unsigned long long) len);
454 }
else if (rc < len) {
455 crm_trace(
"Only sent %d of %llu remaining bytes",
456 rc, (
unsigned long long) len);
462 crm_trace(
"Sent %d bytes: %.100s", rc, buf);
465 return rc < 0 ? rc : total_send;
470 crm_remote_sendv(
crm_remote_t * remote,
struct iovec * iov,
int iovs)
474 for (
int lpc = 0; (lpc < iovs) && (rc >= 0); lpc++) {
475 #ifdef HAVE_GNUTLS_GNUTLS_H
476 if (remote->tls_session) {
477 rc = crm_send_tls(remote->tls_session, iov[lpc].iov_base, iov[lpc].iov_len);
482 rc = crm_send_plaintext(remote->
tcp_socket, iov[lpc].iov_base, iov[lpc].iov_len);
484 rc = -ESOCKTNOSUPPORT;
494 static uint64_t
id = 0;
498 struct crm_remote_header_v0 *header;
500 if (xml_text == NULL) {
501 crm_err(
"Could not send remote message: no message provided");
505 header = calloc(1,
sizeof(
struct crm_remote_header_v0));
506 iov[0].iov_base = header;
507 iov[0].iov_len =
sizeof(
struct crm_remote_header_v0);
509 iov[1].iov_base = xml_text;
510 iov[1].iov_len = 1 + strlen(xml_text);
516 header->payload_offset = iov[0].iov_len;
517 header->payload_uncompressed = iov[1].iov_len;
518 header->size_total = iov[0].iov_len + iov[1].iov_len;
521 (
int)iov[0].iov_len, *(
int*)(
void*)xml_text);
522 rc = crm_remote_sendv(remote, iov, 2);
524 crm_err(
"Could not send remote message: %s " CRM_XS " rc=%d",
528 free(iov[0].iov_base);
529 free(iov[1].iov_base);
543 struct crm_remote_header_v0 *header = crm_remote_header(remote);
545 if (remote->
buffer == NULL || header == NULL) {
550 if (header->payload_compressed) {
552 unsigned int size_u = 1 + header->payload_uncompressed;
553 char *uncompressed = calloc(1, header->payload_offset + size_u);
555 crm_trace(
"Decompressing message data %d bytes into %d bytes",
556 header->payload_compressed, size_u);
558 rc = BZ2_bzBuffToBuffDecompress(uncompressed + header->payload_offset, &size_u,
559 remote->
buffer + header->payload_offset,
560 header->payload_compressed, 1, 0);
563 crm_warn(
"Couldn't decompress v%d message, we only understand v%d",
568 }
else if (rc != BZ_OK) {
575 CRM_ASSERT(size_u == header->payload_uncompressed);
577 memcpy(uncompressed, remote->
buffer, header->payload_offset);
578 remote->
buffer_size = header->payload_offset + size_u;
581 remote->
buffer = uncompressed;
582 header = crm_remote_header(remote);
588 CRM_LOG_ASSERT(remote->
buffer[
sizeof(
struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0);
592 crm_warn(
"Couldn't parse v%d message, we only understand v%d",
595 }
else if (xml == NULL) {
596 crm_err(
"Couldn't parse: '%.120s'", remote->
buffer + header->payload_offset);
614 struct pollfd fds = { 0, };
618 int timeout = total_timeout;
620 #ifdef HAVE_GNUTLS_GNUTLS_H
621 if (remote->tls_session) {
622 void *sock_ptr = gnutls_transport_get_ptr(*remote->tls_session);
624 sock = GPOINTER_TO_INT(sock_ptr);
631 crm_err(
"Unsupported connection type");
648 if (errno == EINTR && (timeout > 0)) {
649 timeout = total_timeout - ((time(NULL) - start) * 1000);
650 if (timeout < 1000) {
655 rc = poll(&fds, 1, timeout);
656 }
while (rc < 0 && errno == EINTR);
658 return (rc < 0)? -errno : rc;
676 size_t read_len =
sizeof(
struct crm_remote_header_v0);
677 struct crm_remote_header_v0 *header = crm_remote_header(remote);
681 read_len = header->size_total;
687 crm_trace(
"Expanding buffer to %llu bytes",
694 #ifdef HAVE_GNUTLS_GNUTLS_H
695 if (remote->tls_session) {
696 rc = gnutls_record_recv(*(remote->tls_session),
699 if (rc == GNUTLS_E_INTERRUPTED) {
701 }
else if (rc == GNUTLS_E_AGAIN) {
704 crm_debug(
"TLS receive failed: %s (%d)", gnutls_strerror(rc), rc);
720 crm_err(
"Unsupported connection type");
721 return -ESOCKTNOSUPPORT;
729 crm_trace(
"Received %u more bytes, %llu total",
732 }
else if (rc == -EINTR || rc == -EAGAIN) {
735 }
else if (rc == 0) {
736 crm_debug(
"EOF encoutered after %llu bytes",
741 crm_debug(
"Error receiving message after %llu bytes: %s (%d)",
747 header = crm_remote_header(remote);
750 crm_trace(
"Read less than the advertised length: %llu < %u bytes",
754 crm_trace(
"Read full message of %llu bytes",
777 time_t start = time(NULL);
778 int remaining_timeout = 0;
780 if (total_timeout == 0) {
781 total_timeout = 10000;
782 }
else if (total_timeout < 0) {
783 total_timeout = 60000;
787 remaining_timeout = total_timeout;
788 while ((remaining_timeout > 0) && !(*disconnected)) {
790 crm_trace(
"Waiting for remote data (%d of %d ms timeout remaining)",
791 remaining_timeout, total_timeout);
795 crm_err(
"Timed out (%d ms) while waiting for remote data",
800 crm_debug(
"Wait for remote data aborted, will try again: %s "
804 rc = crm_remote_recv_once(remote);
807 }
else if (rc == -EAGAIN) {
808 crm_trace(
"Still waiting for remote data");
815 if (rc == -ENOTCONN) {
820 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
826 struct tcp_async_cb_data {
830 void (*callback) (
void *userdata,
int sock);
836 check_connect_finished(gpointer userdata)
838 struct tcp_async_cb_data *cb_data = userdata;
840 int sock = cb_data->sock;
844 socklen_t len =
sizeof(error);
845 struct timeval ts = { 0, };
847 if (cb_data->success == TRUE) {
855 crm_trace(
"fd %d: checking to see if connect finished", sock);
856 cb_arg = select(sock + 1, &rset, &wset, NULL, &ts);
860 if ((errno == EINPROGRESS) || (errno == EAGAIN)) {
862 if ((time(NULL) - cb_data->start) < (cb_data->timeout / 1000)) {
868 crm_trace(
"fd %d: select failed %d connect dispatch ", sock, cb_arg);
870 }
else if (cb_arg == 0) {
871 if ((time(NULL) - cb_data->start) < (cb_data->timeout / 1000)) {
874 crm_debug(
"fd %d: timeout during select", sock);
878 crm_trace(
"fd %d: select returned success", sock);
883 if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
884 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
886 crm_trace(
"fd %d: call to getsockopt failed", sock);
890 crm_trace(
"fd %d: error returned from getsockopt: %d", sock, error);
895 crm_trace(
"neither read nor write set after select");
904 cb_arg = cb_data->sock;
910 if (cb_data->callback) {
911 cb_data->callback(cb_data->userdata, cb_arg);
923 internal_tcp_connect_async(
int sock,
924 const struct sockaddr *addr, socklen_t addrlen,
int timeout ,
925 int *timer_id,
void *userdata,
void (*callback) (
void *userdata,
int sock))
930 struct tcp_async_cb_data *cb_data = NULL;
934 crm_warn(
"Could not set socket non-blocking: %s " CRM_XS " rc=%d",
940 rc = connect(sock, addr, addrlen);
941 if (rc < 0 && (errno != EINPROGRESS) && (errno != EAGAIN)) {
946 cb_data = calloc(1,
sizeof(
struct tcp_async_cb_data));
947 cb_data->userdata = userdata;
948 cb_data->callback = callback;
949 cb_data->sock = sock;
950 cb_data->timeout = timeout;
951 cb_data->start = time(NULL);
958 cb_data->success = TRUE;
970 crm_trace(
"Scheduling check in %dms for whether connect to fd %d finished",
972 timer = g_timeout_add(interval, check_connect_finished, cb_data);
981 internal_tcp_connect(
int sock,
const struct sockaddr *addr, socklen_t addrlen)
983 int rc = connect(sock, addr, addrlen);
994 crm_warn(
"Could not set socket non-blocking: %s " CRM_XS " rc=%d",
1017 int *timer_id,
void *userdata,
1018 void (*callback) (
void *userdata,
int sock))
1020 char buffer[INET6_ADDRSTRLEN];
1021 struct addrinfo *res = NULL;
1022 struct addrinfo *rp = NULL;
1023 struct addrinfo hints;
1024 const char *server =
host;
1026 int sock = -ENOTCONN;
1029 memset(&hints, 0,
sizeof(
struct addrinfo));
1030 hints.ai_family = AF_UNSPEC;
1031 hints.ai_socktype = SOCK_STREAM;
1032 hints.ai_flags = AI_CANONNAME;
1033 ret_ga = getaddrinfo(server, NULL, &hints, &res);
1035 crm_err(
"Unable to get IP address info for %s: %s",
1036 server, gai_strerror(ret_ga));
1039 if (!res || !res->ai_addr) {
1040 crm_err(
"Unable to get IP address info for %s: no result", server);
1045 for (rp = res; rp != NULL; rp = rp->ai_next) {
1046 struct sockaddr *addr = rp->ai_addr;
1052 if (rp->ai_canonname) {
1053 server = res->ai_canonname;
1057 sock = socket(rp->ai_family, SOCK_STREAM, IPPROTO_TCP);
1059 crm_perror(LOG_WARNING,
"creating socket for connection to %s",
1067 if (addr->sa_family == AF_INET6) {
1068 ((
struct sockaddr_in6 *)(
void*)addr)->sin6_port = htons(port);
1070 ((
struct sockaddr_in *)(
void*)addr)->sin_port = htons(port);
1073 memset(buffer, 0,
DIMOF(buffer));
1075 crm_info(
"Attempting TCP connection to %s:%d", buffer, port);
1078 if (internal_tcp_connect_async
1079 (sock, rp->ai_addr, rp->ai_addrlen, timeout, timer_id, userdata, callback) == 0) {
1083 }
else if (internal_tcp_connect(sock, rp->ai_addr, rp->ai_addrlen) == 0) {
1118 switch (((
struct sockaddr*)sa)->sa_family) {
1120 inet_ntop(AF_INET, &(((
struct sockaddr_in *)sa)->sin_addr),
1121 s, INET6_ADDRSTRLEN);
1125 inet_ntop(AF_INET6, &(((
struct sockaddr_in6 *)sa)->sin6_addr),
1126 s, INET6_ADDRSTRLEN);
1130 strcpy(s,
"<invalid>");
1140 struct sockaddr_storage addr;
1141 char addr_str[INET6_ADDRSTRLEN];
1142 #ifdef TCP_USER_TIMEOUT
1148 laddr =
sizeof(addr);
1149 memset(&addr, 0,
sizeof(addr));
1150 csock = accept(ssock, (
struct sockaddr *)&addr, &laddr);
1152 crm_info(
"New remote connection from %s", addr_str);
1155 crm_err(
"accept socket failed");
1161 crm_err(
"Could not set socket non-blocking: %s " CRM_XS " rc=%d",
1167 #ifdef TCP_USER_TIMEOUT
1168 if (sbd_timeout > 0) {
1169 optval = sbd_timeout / 2;
1170 rc = setsockopt(csock, SOL_TCP, TCP_USER_TIMEOUT,
1171 &optval,
sizeof(optval));
1173 crm_err(
"setting TCP_USER_TIMEOUT (%d) on client socket failed",
1192 static int port = 0;
1195 const char *env = getenv(
"PCMK_remote_port");
1199 port = strtol(env, NULL, 10);
1200 if (errno || (port < 1) || (port > 65535)) {
1201 crm_warn(
"Environment variable PCMK_remote_port has invalid value '%s', using %d instead",