1 /*************************************************************************
3 * Copyright 2020 highstreet technologies GmbH and others
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
20 #include "sys_utils.h"
21 #include "log_utils.h"
33 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <linux/if_link.h>
40 static char b64_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
41 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
42 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
43 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
44 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
45 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
46 'w', 'x', 'y', 'z', '0', '1', '2', '3',
47 '4', '5', '6', '7', '8', '9', '+', '/'};
49 static int b64_mod_table[] = {0, 2, 1};
51 bool dir_exists(const char *path) {
55 return (stat(path, &st) != -1);
58 bool file_exists(const char *fname) {
61 return (access(fname, F_OK) != -1);
64 void file_touch(const char *fname, const char *content) {
67 FILE *f = fopen(fname, "w");
69 log_error("fopen failed");
74 fprintf(f, "%s", content);
79 char *file_read_content(const char *fname) {
84 FILE *f = fopen(fname, "rb");
86 fseek(f, 0, SEEK_END);
88 fseek(f, 0, SEEK_SET);
89 buffer = (char*)malloc(sizeof(char) * length);
91 fread(buffer, 1, length, f);
99 int get_int_from_string_with_default(const char *string, int default_value) {
101 int value = default_value;
104 rc = sscanf(string, "%d", &value);
106 value = default_value;
112 char *get_current_date_and_time(void) {
113 char *date_and_time = 0;
116 struct tm tm = *localtime(&t);
120 gettimeofday(&tv, 0);
121 millisec = lrint(tv.tv_usec/1000.0); // Round to nearest millisec
122 if(millisec>=1000) { // Allow for rounding up to nearest second
128 asprintf(&date_and_time, "%04d-%02d-%02dT%02d:%02d:%02d.%01dZ",
129 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
130 tm.tm_hour, tm.tm_min, tm.tm_sec, millisec/100);
132 return date_and_time;
135 long int get_microseconds_since_epoch(void) {
140 gettimeofday(&tv, 0);
141 useconds = t*1000 + tv.tv_usec; //add the microseconds to the seconds
147 bool get_local_ips(const char *ifname, char **ipv4, char **ipv6) {
153 struct ifaddrs *ifaddr;
155 char host[NI_MAXHOST];
161 if (getifaddrs(&ifaddr) == -1) {
163 goto get_local_ips_free;
166 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
167 if (ifa->ifa_addr == NULL) {
171 s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
172 if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
175 goto get_local_ips_free;
178 *ipv4 = strdup(host);
184 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
185 if (ifa->ifa_addr == NULL) {
189 s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in6),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
190 if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET6)) {
193 goto get_local_ips_free;
196 *ipv6 = strdup(host);
213 bool check_port_open(const char *host, uint16_t port) {
216 int simpleSocket = 0;
217 int returnStatus = 0;
218 struct addrinfo simpleServer;
219 struct addrinfo *res;
221 memset(&simpleServer, 0, sizeof simpleServer);
222 simpleServer.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
223 simpleServer.ai_socktype = SOCK_STREAM;
224 simpleServer.ai_flags = AI_ADDRCONFIG;
227 sprintf(sport, "%d", port);
229 returnStatus = getaddrinfo(host, sport, &simpleServer, &res);
230 if(returnStatus != 0) {
234 simpleSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
235 if(simpleSocket < 0) {
240 char s[INET6_ADDRSTRLEN];
241 switch(res->ai_addr->sa_family) {
243 struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr;
244 inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
245 returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
250 struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
251 inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
252 returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
261 if(returnStatus == 0) {
269 char *b64_encode(const unsigned char *data, size_t input_length) {
271 assert(input_length);
273 int output_length = 4 * ((input_length + 2) / 3);
275 char *encoded_data = (char *)malloc(sizeof(char) * (output_length + 1));
276 if (encoded_data == 0) {
280 for (int i = 0, j = 0; i < input_length;) {
281 uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
282 uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
283 uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
285 uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
287 encoded_data[j++] = b64_encoding_table[(triple >> 3 * 6) & 0x3F];
288 encoded_data[j++] = b64_encoding_table[(triple >> 2 * 6) & 0x3F];
289 encoded_data[j++] = b64_encoding_table[(triple >> 1 * 6) & 0x3F];
290 encoded_data[j++] = b64_encoding_table[(triple >> 0 * 6) & 0x3F];
293 for (int i = 0; i < b64_mod_table[input_length % 3]; i++) {
294 encoded_data[output_length - 1 - i] = '=';
297 encoded_data[output_length] = 0;
302 char *str_replace(const char *orig, const char *rep, const char *with) {
307 char *result; // the return string
308 const char *ins; // the next insert point
310 int len_rep; // length of rep (the string to remove)
311 int len_with; // length of with (the string to replace rep with)
312 int len_front; // distance between rep and end of last rep
313 int count; // number of replacements
315 // sanity checks and initialization
320 len_rep = strlen(rep);
322 return 0; // empty rep causes infinite loop during count
328 len_with = strlen(with);
330 // count the number of replacements needed
332 for(count = 0; (tmp = strstr(ins, rep)); ++count) {
336 tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
342 // first time through the loop, all the variable are set correctly
344 // tmp points to the end of the result string
345 // ins points to the next occurrence of rep in orig
346 // orig points to the remainder of orig after "end of rep"
348 ins = strstr(orig, rep);
349 len_front = ins - orig;
350 tmp = strncpy(tmp, orig, len_front) + len_front;
351 tmp = strcpy(tmp, with) + len_with;
352 orig += len_front + len_rep; // move to next "end of rep"
359 char *read_key(const char *filename) {
366 char *key_string = 0;
368 fp = fopen(filename, "r");
370 log_error("could not open file %s", filename);
374 while((read = getline(&line, &len, fp)) != -1) {
375 // we ignore the first and last lines forPrivate keys, Public keys and Certificates
376 if(strstr(line, "PRIVATE KEY-----") || strstr(line, "PUBLIC KEY-----") || strstr(line, "CERTIFICATE-----")) {
384 key_string = (char *)realloc(key_string, strlen(key_string) + read + 1);
385 if(key_string == 0) {
386 log_error("bad allocation");
391 strcat(key_string, line);
394 key_string = strdup(line);
395 if(key_string == 0) {
396 log_error("bad allocation");