--- /dev/null
+/*************************************************************************
+*
+* Copyright 2020 highstreet technologies GmbH and others
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+***************************************************************************/
+
+#define _GNU_SOURCE
+
+#include "sys_utils.h"
+#include "log_utils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <linux/if_link.h>
+#include <assert.h>
+
+static char b64_encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'};
+
+static int b64_mod_table[] = {0, 2, 1};
+
+bool dir_exists(const char *path) {
+ assert(path);
+
+ struct stat st = {0};
+ return (stat(path, &st) != -1);
+}
+
+bool file_exists(const char *fname) {
+ assert(fname);
+
+ return (access(fname, F_OK) != -1);
+}
+
+void file_touch(const char *fname, const char *content) {
+ assert(fname);
+
+ FILE *f = fopen(fname, "w");
+ if(f == 0) {
+ log_error("fopen failed");
+ return;
+ }
+
+ if(content) {
+ fprintf(f, "%s", content);
+ }
+ fclose(f);
+}
+
+char *file_read_content(const char *fname) {
+ assert(fname);
+
+ char *buffer = 0;
+ long length;
+ FILE *f = fopen(fname, "rb");
+ if(f) {
+ fseek(f, 0, SEEK_END);
+ length = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buffer = (char*)malloc(sizeof(char) * length);
+ if(buffer) {
+ fread(buffer, 1, length, f);
+ }
+ fclose(f);
+ }
+
+ return buffer;
+}
+
+int get_int_from_string_with_default(const char *string, int default_value) {
+ int rc;
+ int value = default_value;
+
+ if(string != 0) {
+ rc = sscanf(string, "%d", &value);
+ if (rc != 1) {
+ value = default_value;
+ }
+ }
+ return value;
+}
+
+char *get_current_date_and_time(void) {
+ char *date_and_time = 0;
+
+ time_t t = time(0);
+ struct tm tm = *localtime(&t);
+ struct timeval tv;
+ int millisec;
+
+ gettimeofday(&tv, 0);
+ millisec = lrint(tv.tv_usec/1000.0); // Round to nearest millisec
+ if(millisec>=1000) { // Allow for rounding up to nearest second
+ millisec -=1000;
+ tv.tv_sec++;
+ millisec /= 100;
+ }
+
+ asprintf(&date_and_time, "%04d-%02d-%02dT%02d:%02d:%02d.%01dZ",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, millisec/100);
+
+ return date_and_time;
+}
+
+long int get_microseconds_since_epoch(void) {
+ time_t t = time(0);
+ struct timeval tv;
+ long int useconds;
+
+ gettimeofday(&tv, 0);
+ useconds = t*1000 + tv.tv_usec; //add the microseconds to the seconds
+
+ return useconds;
+}
+
+
+bool get_local_ips(const char *ifname, char **ipv4, char **ipv6) {
+ assert(ifname);
+ assert(ipv4);
+ assert(ipv6);
+
+ int s;
+ struct ifaddrs *ifaddr;
+ struct ifaddrs *ifa;
+ char host[NI_MAXHOST];
+ bool ret = true;
+
+ *ipv4 = 0;
+ *ipv6 = 0;
+
+ if (getifaddrs(&ifaddr) == -1) {
+ ret = false;
+ goto get_local_ips_free;
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL) {
+ continue;
+ }
+
+ s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET)) {
+ if (s != 0) {
+ ret = false;
+ goto get_local_ips_free;
+ }
+
+ *ipv4 = strdup(host);
+ break;
+ }
+ }
+
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr == NULL) {
+ continue;
+ }
+
+ s = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in6),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+ if((strcmp(ifa->ifa_name, ifname) == 0) && (ifa->ifa_addr->sa_family == AF_INET6)) {
+ if (s != 0) {
+ ret = false;
+ goto get_local_ips_free;
+ }
+
+ *ipv6 = strdup(host);
+ break;
+ }
+ }
+
+ get_local_ips_free:
+ if(ret == false) {
+ free(*ipv4);
+ free(*ipv6);
+ *ipv4 = 0;
+ *ipv6 = 0;
+ }
+
+ freeifaddrs(ifaddr);
+ return ret;
+}
+
+bool check_port_open(const char *host, uint16_t port) {
+ assert(host);
+
+ int simpleSocket = 0;
+ int returnStatus = 0;
+ struct addrinfo simpleServer;
+ struct addrinfo *res;
+
+ memset(&simpleServer, 0, sizeof simpleServer);
+ simpleServer.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
+ simpleServer.ai_socktype = SOCK_STREAM;
+ simpleServer.ai_flags = AI_ADDRCONFIG;
+
+ char sport[10];
+ sprintf(sport, "%d", port);
+
+ returnStatus = getaddrinfo(host, sport, &simpleServer, &res);
+ if(returnStatus != 0) {
+ return false;
+ }
+
+ simpleSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if(simpleSocket < 0) {
+ freeaddrinfo(res);
+ return false;
+ }
+
+ char s[INET6_ADDRSTRLEN];
+ switch(res->ai_addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)res->ai_addr;
+ inet_ntop(AF_INET, &(addr_in->sin_addr), s, INET_ADDRSTRLEN);
+ returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
+ break;
+ }
+
+ case AF_INET6: {
+ struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)res->ai_addr;
+ inet_ntop(AF_INET6, &(addr_in6->sin6_addr), s, INET6_ADDRSTRLEN);
+ returnStatus = connect(simpleSocket, res->ai_addr, res->ai_addrlen);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ freeaddrinfo(res);
+ if(returnStatus == 0) {
+ close(simpleSocket);
+ return true;
+ }
+
+ return false;
+}
+
+char *b64_encode(const unsigned char *data, size_t input_length) {
+ assert(data);
+ assert(input_length);
+
+ int output_length = 4 * ((input_length + 2) / 3);
+
+ char *encoded_data = (char *)malloc(sizeof(char) * (output_length + 1));
+ if (encoded_data == 0) {
+ return 0;
+ }
+
+ for (int i = 0, j = 0; i < input_length;) {
+ uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
+ uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
+ uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
+
+ uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+ encoded_data[j++] = b64_encoding_table[(triple >> 3 * 6) & 0x3F];
+ encoded_data[j++] = b64_encoding_table[(triple >> 2 * 6) & 0x3F];
+ encoded_data[j++] = b64_encoding_table[(triple >> 1 * 6) & 0x3F];
+ encoded_data[j++] = b64_encoding_table[(triple >> 0 * 6) & 0x3F];
+ }
+
+ for (int i = 0; i < b64_mod_table[input_length % 3]; i++) {
+ encoded_data[output_length - 1 - i] = '=';
+ }
+
+ encoded_data[output_length] = 0;
+
+ return encoded_data;
+}
+
+char *str_replace(const char *orig, const char *rep, const char *with) {
+ assert(orig);
+ assert(rep);
+ assert(with);
+
+ char *result; // the return string
+ const char *ins; // the next insert point
+ char *tmp; // varies
+ int len_rep; // length of rep (the string to remove)
+ int len_with; // length of with (the string to replace rep with)
+ int len_front; // distance between rep and end of last rep
+ int count; // number of replacements
+
+ // sanity checks and initialization
+ if(!orig || !rep) {
+ return 0;
+ }
+
+ len_rep = strlen(rep);
+ if(len_rep == 0) {
+ return 0; // empty rep causes infinite loop during count
+ }
+
+ if (!with) {
+ with = "";
+ }
+ len_with = strlen(with);
+
+ // count the number of replacements needed
+ ins = orig;
+ for(count = 0; (tmp = strstr(ins, rep)); ++count) {
+ ins = tmp + len_rep;
+ }
+
+ tmp = result = malloc(strlen(orig) + (len_with - len_rep) * count + 1);
+
+ if(!result) {
+ return 0;
+ }
+
+ // first time through the loop, all the variable are set correctly
+ // from here on,
+ // tmp points to the end of the result string
+ // ins points to the next occurrence of rep in orig
+ // orig points to the remainder of orig after "end of rep"
+ while(count--) {
+ ins = strstr(orig, rep);
+ len_front = ins - orig;
+ tmp = strncpy(tmp, orig, len_front) + len_front;
+ tmp = strcpy(tmp, with) + len_with;
+ orig += len_front + len_rep; // move to next "end of rep"
+ }
+
+ strcpy(tmp, orig);
+ return result;
+}
+
+char *read_key(const char *filename) {
+ assert(filename);
+
+ FILE * fp = 0;
+ char * line = 0;
+ size_t len = 0;
+ ssize_t read;
+ char *key_string = 0;
+
+ fp = fopen(filename, "r");
+ if(fp == 0) {
+ log_error("could not open file %s", filename);
+ return 0;
+ }
+
+ while((read = getline(&line, &len, fp)) != -1) {
+ // we ignore the first and last lines forPrivate keys, Public keys and Certificates
+ if(strstr(line, "PRIVATE KEY-----") || strstr(line, "PUBLIC KEY-----") || strstr(line, "CERTIFICATE-----")) {
+ free(line);
+ line = 0;
+ len = 0;
+ continue;
+ }
+ else {
+ if(key_string) {
+ key_string = (char *)realloc(key_string, strlen(key_string) + read + 1);
+ if(key_string == 0) {
+ log_error("bad allocation");
+ free(line);
+ return 0;
+ }
+
+ strcat(key_string, line);
+ }
+ else {
+ key_string = strdup(line);
+ if(key_string == 0) {
+ log_error("bad allocation");
+ free(line);
+ return 0;
+ }
+ }
+
+ free(line);
+ line = 0;
+ len = 0;
+ }
+ }
+
+ fclose(fp);
+ if(line) {
+ free(line);
+ }
+
+ return key_string;
+}