Line data Source code
1 : /** 2 : * @file clustercon.c 3 : * @brief 4 : * 5 : * <+DETAILED+> 6 : * 7 : * @author François Cerbelle (Fanfan), francois@cerbelle.net 8 : * 9 : * @internal 10 : * Created: 25/10/2024 11 : * Revision: none 12 : * Last modified: 2024-11-06 12:55 13 : * Compiler: gcc 14 : * Organization: Cerbelle.net 15 : * Copyright: Copyright (c) 2024, François Cerbelle 16 : * 17 : * This source code is released for free distribution under the terms of the 18 : * GNU General Public License as published by the Free Software Foundation. 19 : */ 20 : 21 : #ifdef HAVE_CONFIG_H 22 : #include "config.h" 23 : #endif 24 : 25 : #include "clustercon.h" 26 : #include "base64.h" /* Base64 encoder and decoder */ 27 : 28 : #include <unistd.h> 29 : #include <string.h> 30 : #ifdef _WIN32 31 : #include <winsock2.h> 32 : #include <ws2tcpip.h> 33 : #else 34 : #include <arpa/inet.h> 35 : #endif 36 : #include <openssl/err.h> 37 : 38 0 : rsclustercon_t* cluster_new(const cluster_t* cluster) { 39 0 : rsclustercon_t* rsclustercon = NULL; 40 : 41 0 : if (NULL==(rsclustercon=malloc(sizeof(struct rsclustercon_s)))) { 42 0 : perror("cluster_new"); 43 0 : return NULL; 44 : } 45 0 : if (NULL==(rsclustercon->host=strdup(cluster->host))) { 46 0 : perror("cluster_new host"); 47 0 : free(rsclustercon); 48 0 : return NULL; 49 : } 50 0 : if (NULL==(rsclustercon->user=strdup(cluster->user))) { 51 0 : perror("cluster_new user"); 52 0 : free(rsclustercon->host); 53 0 : free(rsclustercon); 54 0 : return NULL; 55 : } 56 0 : if (NULL==(rsclustercon->pass=strdup(cluster->pass))) { 57 0 : perror("cluster_new pass"); 58 0 : free(rsclustercon->user); 59 0 : free(rsclustercon->host); 60 0 : free(rsclustercon); 61 0 : return NULL; 62 : } 63 0 : if (NULL==(rsclustercon->cacert=strdup(cluster->cacert))) { 64 0 : perror("cluster_new cacert"); 65 0 : free(rsclustercon->pass); 66 0 : free(rsclustercon->user); 67 0 : free(rsclustercon->host); 68 0 : free(rsclustercon); 69 0 : return NULL; 70 : } 71 0 : rsclustercon->insecure = strcmp(cluster->insecure,"false"); 72 0 : return rsclustercon; 73 : } 74 : 75 0 : int cluster_open(rsclustercon_t* rsclustercon) { 76 : struct sockaddr_in server_addr; 77 : 78 : /* Socket creation */ 79 0 : rsclustercon->sock = socket(AF_INET, SOCK_STREAM, 0); 80 0 : if (rsclustercon->sock < 0) { 81 0 : perror("Socket creation error"); 82 0 : return 1; 83 : } 84 : 85 0 : server_addr.sin_family = AF_INET; 86 0 : server_addr.sin_port = htons(9443); 87 0 : if (inet_pton(AF_INET, rsclustercon->host, &server_addr.sin_addr) <= 0) { 88 0 : perror("Invalid address"); 89 0 : return 2; 90 : } 91 : 92 : /* Server connection */ 93 0 : if (connect(rsclustercon->sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) { 94 0 : perror("Connection failed"); 95 0 : return 3; 96 : } 97 : 98 : /* OpenSSL initialization */ 99 0 : SSL_library_init(); 100 : /* OpenSSL_add_all_algorithms(); */ 101 0 : OpenSSL_add_ssl_algorithms(); 102 0 : SSL_load_error_strings(); 103 : 104 : /* Initialize OpenSSL context */ 105 0 : rsclustercon->ctx = SSL_CTX_new(SSLv23_client_method()); 106 0 : if (!rsclustercon->ctx) { 107 0 : ERR_print_errors_fp(stderr); 108 0 : return 4; 109 : } 110 : 111 : /* Load server certificate or certificate from a certification authority (CA) */ 112 0 : if (strcmp("",rsclustercon->cacert)&&rsclustercon->insecure==0) 113 0 : if (SSL_CTX_load_verify_locations(rsclustercon->ctx, rsclustercon->cacert, NULL) != 1) { 114 0 : ERR_print_errors_fp(stderr); 115 0 : return 5; 116 : } 117 : 118 0 : if (rsclustercon->insecure) 119 : /* Disable certificat check */ 120 0 : SSL_CTX_set_verify(rsclustercon->ctx, SSL_VERIFY_NONE, NULL); 121 : else 122 : /* Enable certificat check */ 123 0 : SSL_CTX_set_verify(rsclustercon->ctx, SSL_VERIFY_PEER, NULL); 124 : 125 : 126 : /* Link SSL configuration to the socket */ 127 0 : rsclustercon->ssl = SSL_new(rsclustercon->ctx); 128 0 : SSL_set_fd(rsclustercon->ssl, rsclustercon->sock); 129 : 130 : /* Initiate SSL connection */ 131 0 : if (SSL_connect(rsclustercon->ssl) <= 0) { 132 0 : ERR_print_errors_fp(stderr); 133 0 : return 6; 134 : } 135 : 136 0 : return 0; 137 : } 138 : 139 0 : cJSON* cluster_queryget(const rsclustercon_t* rsclustercon, const char* endpoint) { 140 : char buf[1024]; 141 : 142 : /* Prepare basic authentication */ 143 : char* auth_encoded; 144 : { 145 : char* auth_clear; 146 0 : if (NULL==(auth_clear = (char*)malloc(strlen(rsclustercon->user)+1+strlen(rsclustercon->pass)+1))) { 147 0 : perror("cluster_queryget malloc(auth)"); 148 0 : return NULL; 149 : }; 150 0 : strcpy(auth_clear,rsclustercon->user); 151 0 : strcat(auth_clear,":"); 152 0 : strcat(auth_clear,rsclustercon->pass); 153 0 : auth_encoded=base64_encode(auth_clear); 154 0 : free(auth_clear); 155 : } 156 : 157 : /* Prepare query */ 158 : char http_request[512]; 159 0 : snprintf(http_request, sizeof(http_request), 160 : "GET %s HTTP/1.1\r\n" 161 : "Host: %s\r\n" 162 : "Content-Type: application/json\r\n" 163 : "Authorization: Basic %s\r\n" 164 : "Connection: close\r\n\r\n", 165 0 : endpoint,rsclustercon->host,auth_encoded 166 : ); 167 0 : free(auth_encoded); 168 : 169 : /* Send query */ 170 0 : SSL_write(rsclustercon->ssl, http_request, strlen(http_request)); 171 : 172 : /* Read reply */ 173 0 : int bytes=0; 174 0 : char* reply=NULL; 175 0 : if (NULL==(reply=strdup(""))) { 176 0 : perror("cluster_queryget strdup"); 177 0 : return NULL; 178 : }; 179 0 : while ((bytes=SSL_read(rsclustercon->ssl, buf, 1024 - 1)) > 0) { 180 0 : buf[bytes] = 0; 181 : char* newreply; 182 0 : if ((newreply=(char*)realloc(reply,strlen(reply)+bytes+1))==NULL) { 183 0 : perror("Unable to allocate reply buffer"); 184 0 : free(reply); 185 0 : return NULL; 186 : } else 187 0 : reply = newreply; 188 0 : strcat(reply, buf); 189 : } 190 : 191 : /* Remove HTTP headers */ 192 : char* http_body; 193 : char* retval_txt; 194 0 : if (NULL==(http_body = strstr(reply,"\r\n\r\n"))) 195 0 : retval_txt= NULL; 196 : else 197 0 : retval_txt=strdup(http_body); 198 0 : free(reply); 199 : 200 0 : cJSON* retval_json = cJSON_Parse(retval_txt); 201 0 : free(retval_txt); 202 : 203 0 : return retval_json; 204 : } 205 : 206 0 : void cluster_close(rsclustercon_t* rsclustercon) { 207 0 : SSL_shutdown(rsclustercon->ssl); 208 0 : SSL_free(rsclustercon->ssl); 209 0 : close(rsclustercon->sock); 210 0 : SSL_CTX_free(rsclustercon->ctx); 211 0 : EVP_cleanup(); 212 0 : } 213 : 214 0 : void cluster_del(rsclustercon_t* rsclustercon) { 215 0 : free(rsclustercon->cacert); 216 0 : free(rsclustercon->pass); 217 0 : free(rsclustercon->user); 218 0 : free(rsclustercon->host); 219 0 : free(rsclustercon); 220 0 : } 221 : 222 : /* vim: set tw=80: */