2020-08-03 19:51:58 +02:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/socket.h>
|
2023-03-29 12:09:40 +02:00
|
|
|
#include <arpa/inet.h>
|
2020-08-03 19:51:58 +02:00
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
#include "tunnel.h"
|
|
|
|
|
|
|
|
#define MODULE_NAME "api"
|
2023-03-29 12:09:40 +02:00
|
|
|
#ifdef MAX_PATH_LEN
|
|
|
|
#undef MAX_PATH_LEN
|
|
|
|
#endif
|
|
|
|
#define MAX_PATH_LEN 108
|
2020-08-03 19:51:58 +02:00
|
|
|
|
2020-12-28 21:39:55 +01:00
|
|
|
static int guard_read(int fd, void* buffer, size_t size)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
int read_len;
|
|
|
|
int st;
|
|
|
|
while(n != (int)size)
|
|
|
|
{
|
|
|
|
read_len = (int)size - n;
|
|
|
|
st = read(fd,buffer + n,read_len);
|
|
|
|
if(st == -1)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME, "Unable to read from #%d: %s", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(st == 0)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME,"Endpoint %d is closed", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
n += st;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int guard_write(int fd, void* buffer, size_t size)
|
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
int write_len;
|
|
|
|
int st;
|
|
|
|
while(n != (int)size)
|
|
|
|
{
|
|
|
|
write_len = (int)size - n;
|
|
|
|
st = write(fd,buffer + n,write_len);
|
|
|
|
if(st == -1)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME,"Unable to write to #%d: %s", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(st == 0)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME,"Endpoint %d is closed", fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
n += st;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
2020-08-03 19:51:58 +02:00
|
|
|
|
2020-11-29 13:27:05 +01:00
|
|
|
static int msg_check_number(int fd, uint16_t number)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-11-29 13:27:05 +01:00
|
|
|
uint16_t value;
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd,&value,sizeof(value)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read integer value: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2021-11-28 14:02:34 +01:00
|
|
|
value = ntohs(value);
|
2020-08-03 19:51:58 +02:00
|
|
|
if(number != value)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Value mismatches: %04X, expected %04X", value, number);
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int msg_read_string(int fd, char* buffer, uint8_t max_length)
|
|
|
|
{
|
|
|
|
uint8_t size;
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd,&size,sizeof(size)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read string size: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(size > max_length)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "String length exceeds the maximal value of %d", max_length);
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd,buffer,size) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read string to buffer: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-28 13:23:30 +01:00
|
|
|
static uint8_t* msg_read_payload(int fd, uint32_t* size)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
|
|
|
uint8_t* data;
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd,size,sizeof(*size)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read payload data size: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-11-28 14:02:34 +01:00
|
|
|
*size = ntohl(*size);
|
2020-08-03 19:51:58 +02:00
|
|
|
if(*size <= 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
data = (uint8_t*) malloc(*size);
|
|
|
|
if(data == NULL)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to allocate memory for payload data: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd,data,*size) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read payload data to buffer: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
free(data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-29 12:09:40 +02:00
|
|
|
static int open_unix_socket(char* path)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
|
|
|
struct sockaddr_un address;
|
|
|
|
address.sun_family = AF_UNIX;
|
|
|
|
|
|
|
|
(void) strncpy(address.sun_path, path, sizeof(address.sun_path));
|
|
|
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
if(fd == -1)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to create Unix domain socket: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(connect(fd, (struct sockaddr*)(&address), sizeof(address)) == -1)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to connect to socket '%s': %s", address.sun_path, strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2020-08-06 23:17:46 +02:00
|
|
|
M_LOG(MODULE_NAME, "Socket %s is created successfully", path);
|
2020-08-03 19:51:58 +02:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2023-03-29 12:09:40 +02:00
|
|
|
static int open_tcp_socket(char * address, int port)
|
|
|
|
{
|
|
|
|
struct sockaddr_in servaddr;
|
|
|
|
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (fd == -1)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME, "Cannot create TCP socket %s:%d: %s",address, port, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bzero(&servaddr, sizeof(servaddr));
|
|
|
|
|
|
|
|
// assign IP, PORT
|
|
|
|
servaddr.sin_family = AF_INET;
|
|
|
|
servaddr.sin_addr.s_addr = inet_addr(address);
|
|
|
|
servaddr.sin_port = htons(port);
|
|
|
|
|
|
|
|
// connect the client socket to server socket
|
|
|
|
if (connect(fd, (struct sockaddr*)&servaddr, sizeof(servaddr))!= 0) {
|
|
|
|
M_ERROR(MODULE_NAME, "Unable to connect to socket '%s:%d': %s", address, port, strerror(errno));
|
|
|
|
close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
M_LOG(MODULE_NAME, "Connected to server: %s:%d at [%d]", address, port, fd);
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int open_socket( char *path)
|
|
|
|
{
|
|
|
|
regmatch_t regex_matches[3];
|
|
|
|
if(strncmp(path,"unix:", 5) == 0)
|
|
|
|
{
|
|
|
|
if(strlen(path + 5) > MAX_PATH_LEN - 1)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME, "socket configuration is too long: %s", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
M_LOG(MODULE_NAME, "Found Unix domain socket configuration: %s", path + 5);
|
|
|
|
return open_unix_socket(path + 5);
|
|
|
|
}
|
|
|
|
else if(regex_match("^([a-zA-Z0-9\\-_\\.]+):([0-9]+)$", path,3, regex_matches))
|
|
|
|
{
|
|
|
|
if(regex_matches[1].rm_eo - regex_matches[1].rm_so > MAX_PATH_LEN - 1)
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME, "socket configuration is too long: %s", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
char address[MAX_PATH_LEN];
|
|
|
|
memcpy(address, path + regex_matches[2].rm_so, regex_matches[2].rm_eo - regex_matches[2].rm_so);
|
|
|
|
int port = atoi(address);
|
|
|
|
(void*) memset(address, 0, MAX_PATH_LEN);
|
|
|
|
memcpy(address, path + regex_matches[1].rm_so, regex_matches[1].rm_eo - regex_matches[1].rm_so);
|
|
|
|
M_LOG(MODULE_NAME, "Found TCP socket configuration: %s:%d", address, port);
|
|
|
|
return open_tcp_socket(address, port);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
M_ERROR(MODULE_NAME, "Unknown socket configuration: %s", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-03 19:51:58 +02:00
|
|
|
|
|
|
|
int msg_read(int fd, tunnel_msg_t* msg)
|
|
|
|
{
|
|
|
|
if(msg_check_number(fd, MSG_MAGIC_BEGIN) == -1)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to check begin magic number");
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd,&msg->header.type,sizeof(msg->header.type)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read msg type: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2020-08-06 23:17:46 +02:00
|
|
|
if(msg->header.type > 0x7)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unknown msg type: %d", msg->header.type);
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd, &msg->header.channel_id, sizeof(msg->header.channel_id)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read msg channel id");
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2021-11-28 14:02:34 +01:00
|
|
|
msg->header.channel_id = ntohs(msg->header.channel_id);
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_read(fd, &msg->header.client_id, sizeof(msg->header.client_id)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read msg client id");
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2021-11-28 14:02:34 +01:00
|
|
|
msg->header.client_id = ntohs(msg->header.client_id);
|
2020-08-03 19:51:58 +02:00
|
|
|
if((msg->data = msg_read_payload(fd, &msg->header.size)) == NULL && msg->header.size != 0)
|
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to read msg payload data");
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(msg_check_number(fd, MSG_MAGIC_END) == -1)
|
|
|
|
{
|
|
|
|
if(msg->data)
|
|
|
|
{
|
|
|
|
free(msg->data);
|
|
|
|
}
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to check end magic number");
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int msg_write(int fd, tunnel_msg_t* msg)
|
|
|
|
{
|
|
|
|
// write begin magic number
|
2021-11-28 14:02:34 +01:00
|
|
|
uint16_t net16;
|
|
|
|
uint32_t net32;
|
|
|
|
net16 = htons(MSG_MAGIC_BEGIN);
|
|
|
|
if(guard_write(fd,&net16, sizeof(net16)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write begin magic number: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// write type
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_write(fd,&msg->header.type, sizeof(msg->header.type)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write msg type: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// write channel id
|
2021-11-28 14:02:34 +01:00
|
|
|
net16 = htons(msg->header.channel_id);
|
|
|
|
if(guard_write(fd,&net16, sizeof(msg->header.channel_id)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write msg channel id: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
//write client id
|
2021-11-28 14:02:34 +01:00
|
|
|
net16 = htons(msg->header.client_id);
|
|
|
|
if(guard_write(fd,&net16, sizeof(msg->header.client_id)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write msg client id: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// write payload len
|
2021-11-28 14:02:34 +01:00
|
|
|
net32 = htonl(msg->header.size);
|
|
|
|
if(guard_write(fd,&net32, sizeof(msg->header.size)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write msg payload length: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
// write payload data
|
|
|
|
if(msg->header.size > 0)
|
|
|
|
{
|
2020-12-28 21:39:55 +01:00
|
|
|
if(guard_write(fd,msg->data, msg->header.size) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write msg payload: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2021-11-28 14:02:34 +01:00
|
|
|
net16 = htons(MSG_MAGIC_END);
|
|
|
|
if(guard_write(fd,&net16, sizeof(net16)) == -1)
|
2020-08-03 19:51:58 +02:00
|
|
|
{
|
2020-08-06 23:17:46 +02:00
|
|
|
M_ERROR(MODULE_NAME, "Unable to write end magic number: %s", strerror(errno));
|
2020-08-03 19:51:58 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
2023-03-29 12:09:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int regex_match(const char* expr,const char* search, int msize, regmatch_t* matches)
|
|
|
|
{
|
|
|
|
regex_t regex;
|
|
|
|
int reti;
|
|
|
|
char msgbuf[100];
|
|
|
|
int ret;
|
|
|
|
/* Compile regular expression */
|
|
|
|
reti = regcomp(®ex, expr, REG_ICASE | REG_EXTENDED);
|
|
|
|
if( reti ){
|
|
|
|
//ERROR("Could not compile regex: %s",expr);
|
|
|
|
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
|
|
|
M_ERROR(MODULE_NAME, "Regex match failed: %s", msgbuf);
|
|
|
|
//return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute regular expression */
|
|
|
|
reti = regexec(®ex, search, msize, matches, 0);
|
|
|
|
if( !reti ){
|
|
|
|
//LOG("Match");
|
|
|
|
ret = 1;
|
|
|
|
}
|
|
|
|
else if( reti == REG_NOMATCH ){
|
|
|
|
//LOG("No match");
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
|
|
|
//ERROR("Regex match failed: %s\n", msgbuf);
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
regfree(®ex);
|
|
|
|
return ret;
|
2020-08-03 19:51:58 +02:00
|
|
|
}
|