Add Remote (credits N7TAE)

develop^2
Geoffrey Merck 5 years ago
parent 0fd7aed8f7
commit 74b8d30bda

4
.gitignore vendored

@ -35,3 +35,7 @@ sgs-xl
#Generated source files #Generated source files
/GitVersion.h /GitVersion.h
/sgs-xl.cfg /sgs-xl.cfg
#certs
sgs-xl.crt
sgs-xl.key

@ -7,20 +7,23 @@ CFGDIR=/usr/local/etc/sgs-xl/
DATADIR=/usr/local/sgs-xl/data/ DATADIR=/usr/local/sgs-xl/data/
# choose this if you want debugging help # choose this if you want debugging help
# CPPFLAGS=-g -ggdb -W -Wall -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\" CPPFLAGS=-g -ggdb -W -Wall -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\"
# or, you can choose this for a much smaller executable without debugging help # or, you can choose this for a much smaller executable without debugging help
CPPFLAGS= -W -Wall -O3 -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\" #CPPFLAGS= -W -Wall -O3 -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\"
SRCS = $(wildcard *.cpp) SRCS = $(wildcard *.cpp)
OBJS = $(SRCS:.cpp=.o) OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d) DEPS = $(SRCS:.cpp=.d)
sgs-xl : GitVersion.h $(OBJS) sgs-xl : GitVersion.h $(OBJS)
g++ $(CPPFLAGS) -o sgs-xl $(OBJS) -lconfig++ -pthread g++ $(CPPFLAGS) -o sgs-xl $(OBJS) -lconfig++ -lssl -lcrypto -pthread
%.o : %.cpp %.o : %.cpp
g++ $(CPPFLAGS) -MMD -MD -c $< -o $@ g++ $(CPPFLAGS) -MMD -MD -c $< -o $@
sgs-xl.crt sgs-xl.key :
openssl req -new -newkey rsa:4096 -days 36500 -nodes -x509 -subj "/CN=Smart Group Server XL" -keyout sgs-xl.key -out sgs-xl.crt
.PHONY: clean .PHONY: clean
clean: clean:
$(RM) GitVersion.h $(OBJS) $(DEPS) sgs-xl $(RM) GitVersion.h $(OBJS) $(DEPS) sgs-xl
@ -36,11 +39,13 @@ newhostfiles :
wget -O $(DATADIR)/DCS_Hosts.txt http://www.pistar.uk/downloads/DCS_Hosts.txt wget -O $(DATADIR)/DCS_Hosts.txt http://www.pistar.uk/downloads/DCS_Hosts.txt
.PHONY: install .PHONY: install
install : newhostfiles sgs-xl install : newhostfiles sgs-xl.key sgs-xl.crt sgs-xl
mkdir -p $(CFGDIR) mkdir -p $(CFGDIR)
mkdir -p $(DATADIR) mkdir -p $(DATADIR)
cp -rf data/* $(DATADIR) cp -rf data/* $(DATADIR)
cp -f sgs-xl.cfg $(CFGDIR) cp -f sgs-xl.cfg $(CFGDIR)
cp -f sgs-xl.crt $(DATADIR)
cp -f sgs-xl.key $(DATADIR)
cp -f sgs-xl $(BINDIR) cp -f sgs-xl $(BINDIR)
cp -f sgs-xl.service /lib/systemd/system cp -f sgs-xl.service /lib/systemd/system
sed -i "s|REPLACEME|$(BINDIR)sgs-xl $(CFGDIR)sgs-xl.cfg|g" /lib/systemd/system/sgs-xl.service sed -i "s|REPLACEME|$(BINDIR)sgs-xl $(CFGDIR)sgs-xl.cfg|g" /lib/systemd/system/sgs-xl.service

@ -39,7 +39,7 @@ git clone git://github.com/F4FXL/smart-group-server-xl.git
``` ```
Install the only needed development library: Install the only needed development library:
``` ```
sudo apt-get install build-essential libconfig++-dev sudo apt-get install build-essential libconfig++-dev openssl libssl-dev
``` ```
Change to the smart-group-server directory and type `make`. This should make the executable, `sgs-xl` without errors or warnings. By default, you will have a group server that can link groups to X-Reflectors or DCS-Reflectors. Of course you can declare an unlinked channel by simply not defining a *reflector* parameter for that channel. Change to the smart-group-server directory and type `make`. This should make the executable, `sgs-xl` without errors or warnings. By default, you will have a group server that can link groups to X-Reflectors or DCS-Reflectors. Of course you can declare an unlinked channel by simply not defining a *reflector* parameter for that channel.

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2011 by Jonathan Naylor G4KLX * Copyright (C) 2011 by Jonathan Naylor G4KLX
* Copyright (c) 2017,2018 by Thomas A. Early N7TAE * Copyright (c) 2017,2018, 2020 by Thomas A. Early N7TAE
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,8 +19,7 @@
#include "RemoteGroup.h" #include "RemoteGroup.h"
CRemoteGroup::CRemoteGroup(const std::string& callsign, const std::string& logoff, const std::string &repeater, const std::string &infoText, CRemoteGroup::CRemoteGroup(const std::string &callsign, const std::string &logoff, const std::string &repeater, const std::string &infoText, const std::string &linkReflector, LINK_STATUS linkStatus, unsigned int userTimeout) :
const std::string &linkReflector, LINK_STATUS linkStatus, unsigned int userTimeout) :
m_callsign(callsign), m_callsign(callsign),
m_logoff(logoff), m_logoff(logoff),
m_repeater(repeater), m_repeater(repeater),
@ -30,8 +29,8 @@ m_linkStatus(linkStatus),
m_userTimeout(userTimeout), m_userTimeout(userTimeout),
m_users() m_users()
{ {
if (m_logoff.compare(" ")) if (logoff.compare(" "))
m_logoff.clear(); logoff.empty();
} }
CRemoteGroup::~CRemoteGroup() CRemoteGroup::~CRemoteGroup()

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2011 by Jonathan Naylor G4KLX * Copyright (C) 2011 by Jonathan Naylor G4KLX
* Copyright (c) 2017,2018 by Thomas A. Early N7TAE * Copyright (c) 2017,2018,2020 by Thomas A. Early N7TAE
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -27,8 +27,7 @@
class CRemoteGroup { class CRemoteGroup {
public: public:
CRemoteGroup(const std::string& callsign, const std::string& logoff, const std::string &repeater, const std::string &infoText, const std::string &linkReflector, CRemoteGroup(const std::string& callsign, const std::string& logoff, const std::string &repeater, const std::string &infoText, const std::string &linkReflector, LINK_STATUS linkStatus, unsigned int userTimeout);
LINK_STATUS linkStatus, unsigned int userTimeout);
~CRemoteGroup(); ~CRemoteGroup();
void addUser(const std::string& callsign, uint32_t timer, uint32_t timeout); void addUser(const std::string& callsign, uint32_t timer, uint32_t timeout);

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX
* Copyright (c) 2017-2018 by Thomas A. Early N7TAE * Copyright (c) 2017-2018,2020 by Thomas A. Early N7TAE
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,165 +20,203 @@
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <list> #include <list>
#include <vector>
#include <sstream>
#include <iterator>
#include "GroupHandler.h"
#include "RemoteHandler.h" #include "RemoteHandler.h"
#include "DExtraHandler.h" #include "DExtraHandler.h"
#include "DStarDefines.h" #include "DStarDefines.h"
#include "DCSHandler.h" #include "DCSHandler.h"
#include "Utils.h" #include "Utils.h"
CRemoteHandler::CRemoteHandler(const std::string &password, unsigned int port, const std::string &address) : bool CRemoteHandler::open(const std::string &password, const unsigned short port, const bool isIPV6)
m_password(password),
m_handler(port, address),
m_random(0U)
{ {
assert(port > 0U); return m_tlsserver.OpenSocket(password, isIPV6 ? "::" : "0.0.0.0", port);
assert(password.size());
} }
CRemoteHandler::~CRemoteHandler() bool CRemoteHandler::process()
{ {
} std::string command;
if (m_tlsserver.GetCommand(command))
return false; // nothing to do...
// parse the command into words
std::stringstream ss(command);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::vector<std::string> cwords(begin, end);
if (cwords.size() == 0) {
return false;
}
bool CRemoteHandler::open() if (0 == cwords[0].compare("halt")) {
{ printf("Received halt command from remote client, shutting down...\n");
return m_handler.open(); //auto groups = CGroupHandler::listGroups();
//for (auto it=groups.begin(); it!=groups.end(); it++) {
// CGroupHandler *group = CGroupHandler::findGroup(*it);
// logoff(group, "ALL ");
//}
return true;
}
if (cwords.size() < 2) {
fprintf(stderr, "Not enough words in the command: [%s]\n", command.c_str());
return false;
}
CUtils::ReplaceChar(cwords[1], '_', ' '); // this is the subscribe callsign
cwords[1].resize(8, ' ');
CGroupHandler *group = CGroupHandler::findGroup(cwords[1]);
if (0 == cwords[0].compare("list")) {
sendGroup(group);
} else if (NULL == group) {
char emsg[128];
snprintf(emsg, 128, "Smart Group [%s] not found", cwords[1].c_str());
m_tlsserver.Write(emsg);
} else {
if (cwords.size() > 2 && 0 == cwords[0].compare("link")) {
CUtils::ReplaceChar(cwords[2], '_', ' ');
cwords[2].resize(8, ' ');
printf("Remote control user has linked \"%s\" to \"%s\"\n", cwords[1].c_str(), cwords[2].c_str());
link(group, cwords[2]);
}
else if (cwords.size() > 1 && 0 == cwords[0].compare("unlink")) {
printf("Remote control user has unlinked \"%s\"\n", cwords[1].c_str());
unlink(group);
}
else if (cwords.size() > 2 && 0 == cwords[0].compare("drop")) {
CUtils::ReplaceChar(cwords[2], '_', ' ');
cwords[2].resize(8, ' ');
printf("Remote control user has logged off \"%s\" from \"%s\"\n", cwords[2].c_str(), cwords[1].c_str());
logoff(group, cwords[2]);
}
else {
printf("The command \"%s\" is bad\n", command.c_str());
}
}
m_tlsserver.CloseClient();
return false;
} }
void CRemoteHandler::process()
void CRemoteHandler::sendGroup(CGroupHandler *group)
{ {
RPH_TYPE type = m_handler.readType(); char msg[128];
switch (type) { if (group) {
case RPHT_LOGOUT: CRemoteGroup *data = group->getInfo();
m_handler.setLoggedIn(false); if (data) {
printf("Remote control user has logged out\n"); snprintf(msg, 128, "Subscribe = %s", data->getCallsign().c_str());
break; m_tlsserver.Write(msg);
case RPHT_LOGIN: snprintf(msg, 128, "Unsubscribe = %s", data->getLogoff().c_str());
m_random = (uint32_t)rand(); m_tlsserver.Write(msg);
m_handler.sendRandom(m_random); snprintf(msg, 128, "Module = %s", data->getRepeater().c_str());
break; m_tlsserver.Write(msg);
case RPHT_HASH: { snprintf(msg, 128, "Description = %s", data->getInfoText().c_str());
bool valid = m_handler.readHash(m_password, m_random); m_tlsserver.Write(msg);
if (valid) { snprintf(msg, 128, "Reflector = %s", data->getReflector().c_str());
printf("Remote control user has logged in\n"); m_tlsserver.Write(msg);
m_handler.setLoggedIn(true); switch (data->getLinkStatus()) {
m_handler.sendACK(); case LS_LINKING_DCS:
} else { case LS_LINKING_DEXTRA:
printf("Remote control user has failed login authentication\n"); m_tlsserver.Write("Link Status = Linking");
m_handler.setLoggedIn(false); break;
m_handler.sendNAK("Invalid password"); case LS_LINKED_DCS:
} case LS_LINKED_DEXTRA:
} m_tlsserver.Write("Link Status = Linked");
break; break;
case RPHT_SMARTGROUP: { default:
std::string callsign = m_handler.readGroup(); m_tlsserver.Write("Link Status = Unlinked");
sendGroup(callsign); break;
}
break;
case RPHT_LINK: {
std::string callsign, reflector;
m_handler.readLink(callsign, reflector);
printf("Remote control user has linked \"%s\" to \"%s\"\n", callsign.c_str(), reflector.c_str());
link(callsign, reflector);
} }
break; snprintf(msg, 128, "User Timeout = %u min", data->getUserTimeout());
case RPHT_UNLINK: { m_tlsserver.Write(msg);
std::string callsign; for (uint32_t i=0; i<data->getUserCount(); i++) {
m_handler.readUnlink(callsign); CRemoteUser *user = data->getUser(i);
printf("Remote control user has unlinked \"%s\"\n", callsign.c_str()); snprintf(msg, 128, " User = %s, timer = %u min, timeout = %u min", user->getCallsign().c_str(), user->getTimer()/60U, user->getTimeout()/60U);
unlink(callsign); m_tlsserver.Write(msg);
} }
break; }
case RPHT_LOGOFF: { delete data;
std::string callsign, user; } else {
m_handler.readLogoff(callsign, user); // no group, so let's summarize all groups
printf("Remote control user has logged off \"%s\" from \"%s\"\n", user.c_str(), callsign.c_str()); auto groups = CGroupHandler::listGroups();
logoff(callsign, user); m_tlsserver.Write("Logon Logoff Channel Description Status Reflector Timeout");
for (auto it=groups.begin(); it!=groups.end(); it++) {
CGroupHandler *group = CGroupHandler::findGroup(*it);
if (group) {
CRemoteGroup *data = group->getInfo();
if (data) {
std::string linkstat;
switch (data->getLinkStatus()) {
case LS_LINKING_DCS:
case LS_LINKING_DEXTRA:
linkstat.assign("Linking ");
break;
case LS_LINKED_DCS:
case LS_LINKED_DEXTRA:
linkstat.assign("Linked ");
break;
default:
linkstat.assign("Unlinked");
break;
}
snprintf(msg, 128, "%s %s %s %s %s %8.8s %4u", data->getCallsign().c_str(), data->getLogoff().c_str(), data->getRepeater().c_str(), data->getInfoText().c_str(), linkstat.c_str(), data->getReflector().c_str(), data->getUserTimeout());
m_tlsserver.Write(msg);
delete data;
}
} }
break; }
default:
break;
} }
} }
void CRemoteHandler::close() void CRemoteHandler::link(CGroupHandler *group, const std::string &reflector)
{
m_handler.close();
}
void CRemoteHandler::sendGroup(const std::string &callsign)
{ {
CGroupHandler *group = CGroupHandler::findGroup(callsign); char msg[128];
if (group == NULL) {
m_handler.sendNAK("Invalid Smart Group callsign");
return;
}
CRemoteGroup *data = group->getInfo(); CRemoteGroup *data = group->getInfo();
if (data != NULL) if (group->remoteLink(reflector))
m_handler.sendGroup(*data); snprintf(msg, 128, "Smart Group %s linked to %s", data->getCallsign().c_str(), reflector.c_str());
delete data;
}
void CRemoteHandler::link(const std::string &callsign, const std::string &reflector)
{
CGroupHandler *smartGroup = CGroupHandler::findGroup(callsign);
if (NULL == smartGroup) {
m_handler.sendNAK(std::string("Invalid Smart Group subscribe call ") + callsign);
return;
}
if (smartGroup->remoteLink(reflector))
m_handler.sendACK();
else else
m_handler.sendNAK("link failed"); snprintf(msg, 128, "Failed to link Smart Group %s to %s", data->getCallsign().c_str(), reflector.c_str());
m_tlsserver.Write(msg);
delete data;
} }
void CRemoteHandler::unlink(const std::string &callsign) void CRemoteHandler::unlink(CGroupHandler *group)
{ {
CGroupHandler *smartGroup = CGroupHandler::findGroup(callsign); char msg[128];
if (NULL == smartGroup) { CRemoteGroup *data = group->getInfo();
m_handler.sendNAK(std::string("Invalid Smart Group subscribe call ") + callsign); switch (group->getLinkType()) {
return; case LT_DEXTRA:
} CDExtraHandler::unlink(group, data->getReflector(), false);
snprintf(msg, 128, "Smart Group %s unlinked from %s", data->getCallsign().c_str(), data->getReflector().c_str());
CRemoteGroup *data = smartGroup->getInfo(); break;
if (data) { case LT_DCS:
switch (smartGroup->getLinkType()) { CDCSHandler::unlink(group, data->getReflector(), false);
case LT_DEXTRA: snprintf(msg, 128, "Smart Group %s unlinked from %s", data->getCallsign().c_str(), data->getReflector().c_str());
CDExtraHandler::unlink(smartGroup, data->getReflector(), false); break;
break; default:
case LT_DCS: snprintf(msg, 128, "Smart Group %s is already unlinked", data->getCallsign().c_str());
CDCSHandler::unlink(smartGroup, data->getReflector(), false); m_tlsserver.Write(msg);
break; delete data;
default: return;
delete data;
m_handler.sendNAK("alread unlinked");
return;
}
delete data;
} else {
m_handler.sendNAK("could not get Smart Group info");
return;
} }
smartGroup->setLinkType(LT_NONE); delete data;
smartGroup->clearReflector(); group->setLinkType(LT_NONE);
m_handler.sendACK(); group->clearReflector();
m_tlsserver.Write(msg);
} }
void CRemoteHandler::logoff(const std::string &callsign, const std::string &user) void CRemoteHandler::logoff(CGroupHandler *group, const std::string &user)
{ {
CGroupHandler *pGroup = CGroupHandler::findGroup(callsign); char msg[128];
if (pGroup == NULL) { CRemoteGroup *data = group->getInfo();
m_handler.sendNAK("Invalid Smart Group callsign"); if (group->logoff(user))
return; snprintf(msg, 128, "Logging off %s from Smart Group %s", user.c_str(), data->getCallsign().c_str());
}
bool res = pGroup->logoff(user);
if (!res)
m_handler.sendNAK("Invalid Smart Group user callsign");
else else
m_handler.sendACK(); snprintf(msg, 128, "Could not logoff %s from Smart Group %s", user.c_str(), data->getCallsign().c_str());
m_tlsserver.Write(msg);
delete data;
} }

@ -22,27 +22,24 @@
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include "RemoteProtocolHandler.h" #include "GroupHandler.h"
#include "Timer.h" #include "TLSServer.h"
class CRemoteHandler { class CRemoteHandler {
public: public:
CRemoteHandler(const std::string &password, unsigned int port, const std::string &address = std::string("")); CRemoteHandler() {};
~CRemoteHandler(); ~CRemoteHandler() {};
bool open(); bool open(const std::string &password, const unsigned short port, const bool isIPV6);
void process(); bool process();
void close();
private: private:
std::string m_password; std::string m_password;
CRemoteProtocolHandler m_handler; CTLSServer m_tlsserver;
uint32_t m_random;
void sendGroup(CGroupHandler *group);
void sendGroup(const std::string &callsign); void link(CGroupHandler *group, const std::string &reflector);
void link(const std::string &callsign, const std::string &reflector); void unlink(CGroupHandler *group);
void unlink(const std::string &callsign); void logoff(CGroupHandler *group, const std::string &user);
void logoff(const std::string &callsign, const std::string &user);
}; };

@ -115,9 +115,9 @@ void CSGSXLThread::run()
CGroupHandler::link(); CGroupHandler::link();
if (m_remoteEnabled && m_remotePassword.size() && m_remotePort > 0U) { if (m_remoteEnabled && m_remotePassword.size() && m_remotePort > 0U) {
m_remote = new CRemoteHandler(m_remotePassword, m_remotePort); m_remote = new CRemoteHandler();
bool res = m_remote->open(); bool res = m_remote->open(m_remotePassword, m_remotePort, false);
if (!res) { if (res) {
delete m_remote; delete m_remote;
m_remote = NULL; m_remote = NULL;
} }
@ -176,7 +176,6 @@ void CSGSXLThread::run()
delete m_irc; delete m_irc;
if (m_remote != NULL) { if (m_remote != NULL) {
m_remote->close();
delete m_remote; delete m_remote;
} }

@ -0,0 +1,230 @@
/*
* Copyright (C) 2020 by Thomas A. Early N7TAE
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <cstring>
#include "TLSServer.h"
CTLSServer::~CTLSServer()
{
CloseClient();
if (m_sock >= 0)
close(m_sock);
if (m_ctx)
SSL_CTX_free(m_ctx);
}
bool CTLSServer::CreateContext(const SSL_METHOD *method)
{
m_ctx = SSL_CTX_new(method);
if (!m_ctx) {
fprintf(stderr, "Unable to create SSL context");
ERR_print_errors_fp(stderr);
return true;
}
return false;
}
// Server Class Definitions
#ifndef CFG_DIR
#define CFG_DIR "/usr/local/etc"
#endif
bool CTLSServer::OpenSocket(const std::string &password, const std::string &address, unsigned short port)
{
m_password.assign(password);
m_address.assign(address);
m_port = port;
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
const SSL_METHOD *method = TLS_server_method();
if (NULL == method) {
perror("Can't set SSL method");
return true;
}
if (CreateContext(method))
return true;
if (0 == SSL_CTX_set_min_proto_version(m_ctx, TLS1_2_VERSION)) {
perror("Can't sent minimum version");
return true;
}
std::string path(DATA_DIR);
std::string file(path+"/sgs-xl.crt");
SSL_CTX_set_ecdh_auto(ctx, 1);
if (0 >= SSL_CTX_use_certificate_file(m_ctx, file.c_str(), SSL_FILETYPE_PEM)) {
ERR_print_errors_fp(stderr);
return true;
}
file.assign(path+"/sgs-xl.key");
if (0 >= SSL_CTX_use_PrivateKey_file(m_ctx, file.c_str(), SSL_FILETYPE_PEM)) {
ERR_print_errors_fp(stderr);
return true;
}
if (CreateSocket())
return true;
return false;
}
bool CTLSServer::CreateSocket()
{
struct sockaddr_storage addr;
memset(&addr, 0, sizeof(struct sockaddr_storage));
int family;
if (m_address.npos != m_address.find(':')) {
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&addr;
a->sin6_family = family = AF_INET6;
a->sin6_port = htons(m_port);
inet_pton(AF_INET6, m_address.c_str(), &(a->sin6_addr));
} else if (m_address.npos != m_address.find('.')) {
struct sockaddr_in *a = (struct sockaddr_in *)&addr;
a->sin_family = family = AF_INET;
a->sin_port = htons(m_port);
inet_pton(AF_INET, m_address.c_str(), &(a->sin_addr));
} else {
fprintf(stderr, "Improper addess [%s], remote socket creation failed!\n", m_address.c_str());
return true;
}
m_sock = socket(family, SOCK_STREAM, 0);
if (m_sock < 0) {
perror("Unable to create socket");
return true;
}
if (0 > bind(m_sock, (struct sockaddr*)&addr, sizeof(addr))) {
perror("Unable to bind");
close(m_sock);
return true;
}
if (0 > listen(m_sock, 1)) {
perror("Unable to listen");
close(m_sock);
return true;
}
return false;
}
bool CTLSServer::GetCommand(std::string &command)
{
struct sockaddr_storage addr;
uint len = sizeof(addr);
memset(&addr, 0, len);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(m_sock, &readfds);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
// don't care about writefds and exceptfds:
// and we will return immediately
int ret = select(m_sock+1, &readfds, NULL, NULL, &tv);
if (ret && FD_ISSET(m_sock, &readfds)) {
// there is someting to read
m_client = accept(m_sock, (struct sockaddr*)&addr, &len);
if (m_client < 0) {
perror("Remote is unable to accept");
return true;
}
if (AF_INET6 == addr.ss_family) {
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&addr;
char s[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(a->sin6_addr), s, INET6_ADDRSTRLEN);
printf("Remote IPV6 client from %s\n", s);
} else {
struct sockaddr_in *a = (struct sockaddr_in *)&addr;
char s[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(a->sin_addr), s, INET_ADDRSTRLEN);
printf("Remote IPV4 client from %s\n", s);
}
m_ssl = SSL_new(m_ctx);
if (NULL == m_ssl) {
CloseClient();
perror("Remote can't create a new SSL");
return true;
} else {
if (0 == SSL_set_fd(m_ssl, m_client)) {
CloseClient();
perror("Remote can't set fd");
return true;
} else {
if (SSL_accept(m_ssl) <= 0) {
CloseClient();
ERR_print_errors_fp(stderr);
return true;
} else {
char buf[256] = { 0 };
SSL_read(m_ssl, buf, 256);
if (m_password.compare(buf)) {
printf("Password [%s] from remote client failed.\n", buf);
SSL_write(m_ssl, "fail", 4);
CloseClient();
return true;
} else {
SSL_write(m_ssl, "pass", 4);
char com[1024] = { 0 };
SSL_read(m_ssl, com, 1024);
command.assign(com);
}
}
}
}
return false;
} else {
// nothing to read
command.clear();
return true;
}
}
int CTLSServer::Write(const char *line)
{
return SSL_write(m_ssl, line, strlen(line));
}
void CTLSServer::CloseClient()
{
if (m_ssl)
SSL_free(m_ssl);
m_ssl = NULL;
if (m_client >= 0)
close(m_client);
m_client = 0;
}

@ -0,0 +1,45 @@
#pragma once
/*
* Copyright (C) 2020 by Thomas A. Early N7TAE
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
class CTLSServer
{
public:
CTLSServer() : m_sock(-1) , m_ctx(NULL) , m_ssl(NULL) , m_client(-1) {}
~CTLSServer();
virtual bool OpenSocket(const std::string &password, const std::string &address, unsigned short port);
bool GetCommand(std::string &command);
int Write(const char *line);
void CloseClient();
private:
bool CreateContext(const SSL_METHOD *method);
virtual bool CreateSocket();
int m_sock;
SSL_CTX *m_ctx;
SSL *m_ssl;
int m_client;
std::string m_address, m_password;
unsigned short m_port;
};
Loading…
Cancel
Save

Powered by TurnKey Linux.