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 = NULL;
232 if (cred_type == GNUTLS_CRD_ANON) {
240 if (session == NULL) {
241 rc = GNUTLS_E_MEMORY_ERROR;
245 rc = gnutls_init(session, conn_type);
246 if (rc != GNUTLS_E_SUCCESS) {
254 rc = gnutls_priority_set_direct(*session, prio, NULL);
255 if (rc != GNUTLS_E_SUCCESS) {
258 if (conn_type == GNUTLS_CLIENT) {
259 pcmk__set_minimum_dh_bits(session);
262 gnutls_transport_set_ptr(*session,
263 (gnutls_transport_ptr_t) GINT_TO_POINTER(csock));
265 rc = gnutls_credentials_set(*session, cred_type, credentials);
266 if (rc != GNUTLS_E_SUCCESS) {
272 crm_err(
"Could not initialize %s TLS %s session: %s " 273 CRM_XS " rc=%d priority='%s'",
274 (cred_type == GNUTLS_CRD_ANON)?
"anonymous" :
"PSK",
275 (conn_type == GNUTLS_SERVER)?
"server" :
"client",
276 gnutls_strerror(rc), rc, prio);
277 if (session != NULL) {
278 gnutls_free(session);
299 pcmk__init_tls_dh(gnutls_dh_params_t *dh_params)
301 int rc = GNUTLS_E_SUCCESS;
302 unsigned int dh_bits = 0;
304 rc = gnutls_dh_params_init(dh_params);
305 if (rc != GNUTLS_E_SUCCESS) {
309 #ifdef HAVE_GNUTLS_SEC_PARAM_TO_PK_BITS 310 dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH,
311 GNUTLS_SEC_PARAM_NORMAL);
313 rc = GNUTLS_E_DH_PRIME_UNACCEPTABLE;
319 dh_bits = pcmk__bound_dh_bits(dh_bits);
321 crm_info(
"Generating Diffie-Hellman parameters with %u-bit prime for TLS",
323 rc = gnutls_dh_params_generate2(*dh_params, dh_bits);
324 if (rc != GNUTLS_E_SUCCESS) {
331 crm_err(
"Could not initialize Diffie-Hellman parameters for TLS: %s " 332 CRM_XS " rc=%d", gnutls_strerror(rc), rc);
357 rc = gnutls_handshake(*client->
remote->tls_session);
358 }
while (rc == GNUTLS_E_INTERRUPTED);
360 if (rc == GNUTLS_E_AGAIN) {
365 }
else if (rc != GNUTLS_E_SUCCESS) {
374 const char *unsent = buf;
383 crm_trace(
"Message size: %llu", (
unsigned long long) len);
386 rc = gnutls_record_send(*session, unsent, len);
388 if (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN) {
390 (
unsigned long long) len);
395 gnutls_strerror(rc), rc);
399 }
else if (rc < len) {
400 crm_debug(
"Sent %d of %llu bytes", rc, (
unsigned long long) len);
409 return rc < 0 ? rc : total_send;
414 crm_send_plaintext(
int sock,
const char *buf,
size_t len)
418 const char *unsent = buf;
426 crm_trace(
"Message on socket %d: size=%llu",
427 sock, (
unsigned long long) len);
429 rc = write(sock, unsent, len);
439 "Could only write %d of the remaining %llu bytes",
440 rc, (
unsigned long long) len);
444 }
else if (rc < len) {
445 crm_trace(
"Only sent %d of %llu remaining bytes",
446 rc, (
unsigned long long) len);
452 crm_trace(
"Sent %d bytes: %.100s", rc, buf);
455 return rc < 0 ? rc : total_send;
460 crm_remote_sendv(
crm_remote_t * remote,
struct iovec * iov,
int iovs)
464 for (
int lpc = 0; (lpc < iovs) && (rc >= 0); lpc++) {
465 #ifdef HAVE_GNUTLS_GNUTLS_H 466 if (remote->tls_session) {
467 rc = crm_send_tls(remote->tls_session, iov[lpc].iov_base, iov[lpc].iov_len);
472 rc = crm_send_plaintext(remote->
tcp_socket, iov[lpc].iov_base, iov[lpc].iov_len);
474 rc = -ESOCKTNOSUPPORT;
484 static uint64_t
id = 0;
488 struct crm_remote_header_v0 *header;
490 if (xml_text == NULL) {
491 crm_err(
"Could not send remote message: no message provided");
495 header = calloc(1,
sizeof(
struct crm_remote_header_v0));
496 iov[0].iov_base = header;
497 iov[0].iov_len =
sizeof(
struct crm_remote_header_v0);
499 iov[1].iov_base = xml_text;
500 iov[1].iov_len = 1 + strlen(xml_text);
506 header->payload_offset = iov[0].iov_len;
507 header->payload_uncompressed = iov[1].iov_len;
508 header->size_total = iov[0].iov_len + iov[1].iov_len;
511 (
int)iov[0].iov_len, *(
int*)(
void*)xml_text);
512 rc = crm_remote_sendv(remote, iov, 2);
514 crm_err(
"Could not send remote message: %s " CRM_XS " rc=%d",
518 free(iov[0].iov_base);
519 free(iov[1].iov_base);
533 struct crm_remote_header_v0 *header = crm_remote_header(remote);
535 if (remote->
buffer == NULL || header == NULL) {
540 if (header->payload_compressed) {
542 unsigned int size_u = 1 + header->payload_uncompressed;
543 char *uncompressed = calloc(1, header->payload_offset + size_u);
545 crm_trace(
"Decompressing message data %d bytes into %d bytes",
546 header->payload_compressed, size_u);
548 rc = BZ2_bzBuffToBuffDecompress(uncompressed + header->payload_offset, &size_u,
549 remote->
buffer + header->payload_offset,
550 header->payload_compressed, 1, 0);
553 crm_warn(
"Couldn't decompress v%d message, we only understand v%d",
558 }
else if (rc != BZ_OK) {
565 CRM_ASSERT(size_u == header->payload_uncompressed);
567 memcpy(uncompressed, remote->
buffer, header->payload_offset);
568 remote->
buffer_size = header->payload_offset + size_u;
571 remote->
buffer = uncompressed;
572 header = crm_remote_header(remote);
578 CRM_LOG_ASSERT(remote->
buffer[
sizeof(
struct crm_remote_header_v0) + header->payload_uncompressed - 1] == 0);
582 crm_warn(
"Couldn't parse v%d message, we only understand v%d",
585 }
else if (xml == NULL) {
586 crm_err(
"Couldn't parse: '%.120s'", remote->
buffer + header->payload_offset);
604 struct pollfd fds = { 0, };
608 int timeout = total_timeout;
610 #ifdef HAVE_GNUTLS_GNUTLS_H 611 if (remote->tls_session) {
612 void *sock_ptr = gnutls_transport_get_ptr(*remote->tls_session);
614 sock = GPOINTER_TO_INT(sock_ptr);
621 crm_err(
"Unsupported connection type");
638 if (errno == EINTR && (timeout > 0)) {
639 timeout = total_timeout - ((time(NULL) - start) * 1000);
640 if (timeout < 1000) {
645 rc = poll(&fds, 1, timeout);
646 }
while (rc < 0 && errno == EINTR);
648 return (rc < 0)? -errno : rc;
666 size_t read_len =
sizeof(
struct crm_remote_header_v0);
667 struct crm_remote_header_v0 *header = crm_remote_header(remote);
671 read_len = header->size_total;
677 crm_trace(
"Expanding buffer to %llu bytes",
684 #ifdef HAVE_GNUTLS_GNUTLS_H 685 if (remote->tls_session) {
686 rc = gnutls_record_recv(*(remote->tls_session),
689 if (rc == GNUTLS_E_INTERRUPTED) {
691 }
else if (rc == GNUTLS_E_AGAIN) {
694 crm_debug(
"TLS receive failed: %s (%d)", gnutls_strerror(rc), rc);
710 crm_err(
"Unsupported connection type");
711 return -ESOCKTNOSUPPORT;
719 crm_trace(
"Received %u more bytes, %llu total",
722 }
else if (rc == -EINTR || rc == -EAGAIN) {
725 }
else if (rc == 0) {
726 crm_debug(
"EOF encoutered after %llu bytes",
731 crm_debug(
"Error receiving message after %llu bytes: %s (%d)",
737 header = crm_remote_header(remote);
740 crm_trace(
"Read less than the advertised length: %llu < %u bytes",
744 crm_trace(
"Read full message of %llu bytes",
767 time_t start = time(NULL);
768 int remaining_timeout = 0;
770 if (total_timeout == 0) {
771 total_timeout = 10000;
772 }
else if (total_timeout < 0) {
773 total_timeout = 60000;
777 remaining_timeout = total_timeout;
778 while ((remaining_timeout > 0) && !(*disconnected)) {
780 crm_trace(
"Waiting for remote data (%d of %d ms timeout remaining)",
781 remaining_timeout, total_timeout);
785 crm_err(
"Timed out (%d ms) while waiting for remote data",
790 crm_debug(
"Wait for remote data aborted, will try again: %s " 794 rc = crm_remote_recv_once(remote);
797 }
else if (rc == -EAGAIN) {
798 crm_trace(
"Still waiting for remote data");
805 if (rc == -ENOTCONN) {
810 remaining_timeout = total_timeout - ((time(NULL) - start) * 1000);
816 struct tcp_async_cb_data {
820 void (*callback) (
void *userdata,
int sock);
826 check_connect_finished(gpointer userdata)
828 struct tcp_async_cb_data *cb_data = userdata;
830 int sock = cb_data->sock;
834 socklen_t len =
sizeof(error);
835 struct timeval ts = { 0, };
837 if (cb_data->success == TRUE) {
845 crm_trace(
"fd %d: checking to see if connect finished", sock);
846 cb_arg = select(sock + 1, &rset, &wset, NULL, &ts);
850 if ((errno == EINPROGRESS) || (errno == EAGAIN)) {
852 if ((time(NULL) - cb_data->start) < (cb_data->timeout / 1000)) {
858 crm_trace(
"fd %d: select failed %d connect dispatch ", sock, cb_arg);
860 }
else if (cb_arg == 0) {
861 if ((time(NULL) - cb_data->start) < (cb_data->timeout / 1000)) {
864 crm_debug(
"fd %d: timeout during select", sock);
868 crm_trace(
"fd %d: select returned success", sock);
873 if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
874 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
876 crm_trace(
"fd %d: call to getsockopt failed", sock);
880 crm_trace(
"fd %d: error returned from getsockopt: %d", sock, error);
885 crm_trace(
"neither read nor write set after select");
894 cb_arg = cb_data->sock;
900 if (cb_data->callback) {
901 cb_data->callback(cb_data->userdata, cb_arg);
913 internal_tcp_connect_async(
int sock,
914 const struct sockaddr *addr, socklen_t addrlen,
int timeout ,
915 int *timer_id,
void *userdata,
void (*callback) (
void *userdata,
int sock))
920 struct tcp_async_cb_data *cb_data = NULL;
924 crm_warn(
"Could not set socket non-blocking: %s " CRM_XS " rc=%d",
930 rc = connect(sock, addr, addrlen);
931 if (rc < 0 && (errno != EINPROGRESS) && (errno != EAGAIN)) {
936 cb_data = calloc(1,
sizeof(
struct tcp_async_cb_data));
937 cb_data->userdata = userdata;
938 cb_data->callback = callback;
939 cb_data->sock = sock;
940 cb_data->timeout = timeout;
941 cb_data->start = time(NULL);
948 cb_data->success = TRUE;
960 crm_trace(
"Scheduling check in %dms for whether connect to fd %d finished",
962 timer = g_timeout_add(interval, check_connect_finished, cb_data);
971 internal_tcp_connect(
int sock,
const struct sockaddr *addr, socklen_t addrlen)
973 int rc = connect(sock, addr, addrlen);
984 crm_warn(
"Could not set socket non-blocking: %s " CRM_XS " rc=%d",
1007 int *timer_id,
void *userdata,
1008 void (*callback) (
void *userdata,
int sock))
1010 char buffer[INET6_ADDRSTRLEN];
1011 struct addrinfo *res = NULL;
1012 struct addrinfo *rp = NULL;
1013 struct addrinfo hints;
1014 const char *server =
host;
1016 int sock = -ENOTCONN;
1019 memset(&hints, 0,
sizeof(
struct addrinfo));
1020 hints.ai_family = AF_UNSPEC;
1021 hints.ai_socktype = SOCK_STREAM;
1022 hints.ai_flags = AI_CANONNAME;
1023 ret_ga = getaddrinfo(server, NULL, &hints, &res);
1025 crm_err(
"Unable to get IP address info for %s: %s",
1026 server, gai_strerror(ret_ga));
1029 if (!res || !res->ai_addr) {
1030 crm_err(
"Unable to get IP address info for %s: no result", server);
1035 for (rp = res; rp != NULL; rp = rp->ai_next) {
1036 struct sockaddr *addr = rp->ai_addr;
1042 if (rp->ai_canonname) {
1043 server = res->ai_canonname;
1045 crm_debug(
"Got canonical name %s for %s", server, host);
1047 sock = socket(rp->ai_family, SOCK_STREAM, IPPROTO_TCP);
1049 crm_perror(LOG_WARNING,
"creating socket for connection to %s",
1057 if (addr->sa_family == AF_INET6) {
1058 ((
struct sockaddr_in6 *)(
void*)addr)->sin6_port = htons(port);
1060 ((
struct sockaddr_in *)(
void*)addr)->sin_port = htons(port);
1063 memset(buffer, 0,
DIMOF(buffer));
1065 crm_info(
"Attempting TCP connection to %s:%d", buffer, port);
1068 if (internal_tcp_connect_async
1069 (sock, rp->ai_addr, rp->ai_addrlen, timeout, timer_id, userdata, callback) == 0) {
1073 }
else if (internal_tcp_connect(sock, rp->ai_addr, rp->ai_addrlen) == 0) {
1108 switch (((
struct sockaddr*)sa)->sa_family) {
1110 inet_ntop(AF_INET, &(((
struct sockaddr_in *)sa)->sin_addr),
1111 s, INET6_ADDRSTRLEN);
1115 inet_ntop(AF_INET6, &(((
struct sockaddr_in6 *)sa)->sin6_addr),
1116 s, INET6_ADDRSTRLEN);
1120 strcpy(s,
"<invalid>");
1130 struct sockaddr_storage addr;
1131 char addr_str[INET6_ADDRSTRLEN];
1132 #ifdef TCP_USER_TIMEOUT 1138 laddr =
sizeof(addr);
1139 memset(&addr, 0,
sizeof(addr));
1140 csock = accept(ssock, (
struct sockaddr *)&addr, &laddr);
1142 crm_info(
"New remote connection from %s", addr_str);
1145 crm_err(
"accept socket failed");
1151 crm_err(
"Could not set socket non-blocking: %s " CRM_XS " rc=%d",
1157 #ifdef TCP_USER_TIMEOUT 1158 if (sbd_timeout > 0) {
1159 optval = sbd_timeout / 2;
1160 rc = setsockopt(csock, SOL_TCP, TCP_USER_TIMEOUT,
1161 &optval,
sizeof(optval));
1163 crm_err(
"setting TCP_USER_TIMEOUT (%d) on client socket failed",
1182 static int port = 0;
1185 const char *env = getenv(
"PCMK_remote_port");
1189 port = strtol(env, NULL, 10);
1190 if (errno || (port < 1) || (port > 65535)) {
1191 crm_warn(
"Environment variable PCMK_remote_port has invalid value '%s', using %d instead",
const char * pcmk_strerror(int rc)
const char * bz2_strerror(int rc)
long crm_get_sbd_timeout(void)
uint32_t payload_compressed
int crm_parse_int(const char *text, const char *default_text)
Parse an integer value from a string.
struct crm_remote_s * remote
uint32_t payload_uncompressed
#define CRM_LOG_ASSERT(expr)
int crm_default_remote_port()
Get the default remote connection TCP port on this host.
Wrappers for and extensions to glib mainloop.
xmlNode * string2xml(const char *input)
int crm_remote_send(crm_remote_t *remote, xmlNode *msg)
#define DEFAULT_REMOTE_PORT
#define PCMK_GNUTLS_PRIORITIES
int crm_remote_tcp_connect(const char *host, int port)
#define crm_warn(fmt, args...)
#define crm_debug(fmt, args...)
void crm_sockaddr2str(void *sa, char *s)
Convert an IP address (IPv4 or IPv6) to a string for logging.
int crm_remote_accept(int ssock)
#define crm_trace(fmt, args...)
int crm_set_nonblocking(int fd)
int crm_remote_ready(crm_remote_t *remote, int total_timeout)
Wrappers for and extensions to libxml2.
struct tcp_async_cb_data __attribute__
#define crm_perror(level, fmt, args...)
Log a system error message.
#define REMOTE_MSG_VERSION
#define crm_err(fmt, args...)
char * dump_xml_unformatted(xmlNode *msg)
xmlNode * crm_remote_parse_buffer(crm_remote_t *remote)
int crm_remote_tcp_connect_async(const char *host, int port, int timeout, int *timer_id, void *userdata, void(*callback)(void *userdata, int sock))
#define crm_info(fmt, args...)
gboolean crm_remote_recv(crm_remote_t *remote, int total_timeout, int *disconnected)