diff --git a/Makefile b/Makefile index b575c99..e8c8469 100644 --- a/Makefile +++ b/Makefile @@ -105,13 +105,14 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = uxlogger.$(OBJEXT) msgheader.$(OBJEXT) \ - interface.$(OBJEXT) iprouter.$(OBJEXT) uxcontrol.pb.$(OBJEXT) + interface.$(OBJEXT) iprouter.$(OBJEXT) stringaux.$(OBJEXT) \ + networkaux.$(OBJEXT) uxcontrol.pb.$(OBJEXT) am_helmetcli_OBJECTS = helmetcli.$(OBJEXT) uxclient.$(OBJEXT) \ $(am__objects_1) helmetcli_OBJECTS = $(am_helmetcli_OBJECTS) helmetcli_LDADD = $(LDADD) am_helmetsrv_OBJECTS = helmetsrv.$(OBJEXT) tservice.$(OBJEXT) \ - sockhand.$(OBJEXT) $(am__objects_1) + sockhand.$(OBJEXT) srvconfig.$(OBJEXT) $(am__objects_1) helmetsrv_OBJECTS = $(am_helmetsrv_OBJECTS) helmetsrv_LDADD = $(LDADD) AM_V_P = $(am__v_P_$(V)) @@ -206,7 +207,7 @@ distcleancheck_listfiles = \ ACLOCAL = ${SHELL} '/home/ziggi/Projects/stvpn/missing' aclocal-1.17 AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 1 -ASTYLE = /bin/astyle +ASTYLE = /usr/bin/astyle AUTOCONF = ${SHELL} '/home/ziggi/Projects/stvpn/missing' autoconf AUTOHEADER = ${SHELL} '/home/ziggi/Projects/stvpn/missing' autoheader AUTOMAKE = ${SHELL} '/home/ziggi/Projects/stvpn/missing' automake-1.17 @@ -219,7 +220,7 @@ CSCOPE = cscope CTAGS = ctags CXX = g++ CXXDEPMODE = depmode=none -CXXFLAGS = -O1 -std=c++23 -Wall -I. -pthread -D_GNU_SOURCE=1 -MMD -MP +CXXFLAGS = -O -std=c++23 -Wall -I. -pthread -D_GNU_SOURCE=1 -MMD -MP CYGPATH_W = echo DEFS = -DHAVE_CONFIG_H DEPDIR = .deps @@ -228,7 +229,7 @@ ECHO_N = -n ECHO_T = ETAGS = etags EXEEXT = -INSTALL = /bin/install -c +INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} @@ -238,7 +239,7 @@ LIBOBJS = LIBS = -Wl,--as-need -lprotobuf LTLIBOBJS = MAKEINFO = ${SHELL} '/home/ziggi/Projects/stvpn/missing' makeinfo -MKDIR_P = /bin/mkdir -p +MKDIR_P = /usr/bin/mkdir -p OBJEXT = o PACKAGE = helmet PACKAGE_BUGREPORT = @@ -248,7 +249,7 @@ PACKAGE_TARNAME = helmet PACKAGE_URL = PACKAGE_VERSION = 0.0.1 PATH_SEPARATOR = : -PROTOC = /bin/protoc +PROTOC = /usr/bin/protoc RANLIB = ranlib SET_MAKE = SHELL = /bin/bash @@ -304,6 +305,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo subdir-objects helmetsrv_SOURCES = helmetsrv.cpp \ tservice.cpp tservice.hpp \ sockhand.cpp dockhand.hpp \ + srvconfig.cpp srvconfig.hpp \ $(helmet_SOURCES) helmetcli_SOURCES = helmetcli.cpp \ @@ -315,6 +317,8 @@ helmet_SOURCES = \ msgheader.cpp msgheader.hpp \ interface.cpp interface.hpp \ iprouter.cpp iprouter.hpp \ + stringaux.cpp stringaux.hpp \ + networkaux.cpp networkaux.hpp \ uxcontrol.pb.cc uxcontrol.pb.h ASTYLE_OPTS = --indent=spaces=8 --style=java diff --git a/Makefile.am b/Makefile.am index dd86bfe..74c1110 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo subdir-objects -CXXFLAGS = -O1 -std=c++23 -Wall -I. -pthread -D_GNU_SOURCE=1 -MMD -MP +CXXFLAGS = -O -std=c++23 -Wall -I. -pthread -D_GNU_SOURCE=1 -MMD -MP LDFLAGS = -pthread LIBS = -Wl,--as-need -lprotobuf @@ -10,6 +10,7 @@ sbin_PROGRAMS = helmetsrv helmetcli helmetsrv_SOURCES = helmetsrv.cpp \ tservice.cpp tservice.hpp \ sockhand.cpp dockhand.hpp \ + srvconfig.cpp srvconfig.hpp \ $(helmet_SOURCES) helmetcli_SOURCES = helmetcli.cpp \ @@ -21,6 +22,8 @@ helmet_SOURCES = \ msgheader.cpp msgheader.hpp \ interface.cpp interface.hpp \ iprouter.cpp iprouter.hpp \ + stringaux.cpp stringaux.hpp \ + networkaux.cpp networkaux.hpp \ uxcontrol.pb.cc uxcontrol.pb.h ASTYLE_OPTS = --indent=spaces=8 --style=java diff --git a/Makefile.in b/Makefile.in index f01c3dd..6f0647f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -105,13 +105,14 @@ CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = uxlogger.$(OBJEXT) msgheader.$(OBJEXT) \ - interface.$(OBJEXT) iprouter.$(OBJEXT) uxcontrol.pb.$(OBJEXT) + interface.$(OBJEXT) iprouter.$(OBJEXT) stringaux.$(OBJEXT) \ + networkaux.$(OBJEXT) uxcontrol.pb.$(OBJEXT) am_helmetcli_OBJECTS = helmetcli.$(OBJEXT) uxclient.$(OBJEXT) \ $(am__objects_1) helmetcli_OBJECTS = $(am_helmetcli_OBJECTS) helmetcli_LDADD = $(LDADD) am_helmetsrv_OBJECTS = helmetsrv.$(OBJEXT) tservice.$(OBJEXT) \ - sockhand.$(OBJEXT) $(am__objects_1) + sockhand.$(OBJEXT) srvconfig.$(OBJEXT) $(am__objects_1) helmetsrv_OBJECTS = $(am_helmetsrv_OBJECTS) helmetsrv_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) @@ -219,7 +220,7 @@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = -O1 -std=c++23 -Wall -I. -pthread -D_GNU_SOURCE=1 -MMD -MP +CXXFLAGS = -O -std=c++23 -Wall -I. -pthread -D_GNU_SOURCE=1 -MMD -MP CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ @@ -304,6 +305,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo subdir-objects helmetsrv_SOURCES = helmetsrv.cpp \ tservice.cpp tservice.hpp \ sockhand.cpp dockhand.hpp \ + srvconfig.cpp srvconfig.hpp \ $(helmet_SOURCES) helmetcli_SOURCES = helmetcli.cpp \ @@ -315,6 +317,8 @@ helmet_SOURCES = \ msgheader.cpp msgheader.hpp \ interface.cpp interface.hpp \ iprouter.cpp iprouter.hpp \ + stringaux.cpp stringaux.hpp \ + networkaux.cpp networkaux.hpp \ uxcontrol.pb.cc uxcontrol.pb.h ASTYLE_OPTS = --indent=spaces=8 --style=java diff --git a/helmetd b/helmetd deleted file mode 100755 index b8078e1..0000000 Binary files a/helmetd and /dev/null differ diff --git a/helmetsrv.conf b/helmetsrv.conf new file mode 100644 index 0000000..6e0a5bb --- /dev/null +++ b/helmetsrv.conf @@ -0,0 +1,2 @@ +listenport = 1025; +tunnelnet = 10.1.1.0/24; diff --git a/helmetsrv.cpp b/helmetsrv.cpp index f18c64f..8054508 100644 --- a/helmetsrv.cpp +++ b/helmetsrv.cpp @@ -5,17 +5,39 @@ #include #include +#include -int main(int argc, char** argv) { - TCPService service(1025); +std::expected Run() { + ServConfig config; + + auto readRes = config.Read("helmetsrv.conf"); + if (!readRes) { + return std::unexpected("Read config error: " + readRes.error()); + } + auto validateRes = config.Validate(); + if (!validateRes) { + return std::unexpected("Validate config error: " + validateRes.error()); + } + auto listport = config.Listenport(); + auto localnets = config.Localnets(); + auto tunnelnet = config.Tunnelnet(); + TunService service(listport, tunnelnet, localnets); auto bindRes = service.Bind(); if (!bindRes) { - uxlogger.Log("Bind error: " + bindRes.error()); - return 1; + return std::unexpected("Bind error: " + bindRes.error()); } + uxlogger.Info(std::format("Listening on port {}", listport)); auto listenRes = service.Listen(); if (!listenRes) { - uxlogger.Log("Listen error: " + listenRes.error()); + return std::unexpected("Listen error: " + listenRes.error()); + } + return {}; +} + +int main(int argc, char** argv) { + auto runRes = Run(); + if (!runRes) { + uxlogger.Log(runRes.error()); return 1; } return 0; diff --git a/interface.cpp b/interface.cpp index 79a9f59..a461224 100644 --- a/interface.cpp +++ b/interface.cpp @@ -155,14 +155,12 @@ std::expected Interface::SetIP4Address(std::string ipaddr) { std::string error = std::strerror(errnocopy); return std::unexpected("Set address error: " + error); } - int sockfd = 0; if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { int errnocopy = errno; std::string error = std::strerror(errnocopy); return std::unexpected("Set address error: " + error); } - if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { close(sockfd); int errnocopy = errno; @@ -177,8 +175,7 @@ std::expected Interface::SetIP4Netmask(int prefix) { if (prefix < 0 || prefix > 32) { return std::unexpected("Invalid prefix"); } - //uint32_t mask = (prefix == 0) ? 0 : (~0U << (32 - prefix)); - uint32_t mask = (prefix == 0) ? 0 : htonl(~((1U << (32 - prefix)) - 1)); + uint32_t mask = (prefix == 0) ? 0 : (~0U << (32 - prefix)); struct in_addr maskaddr; maskaddr.s_addr = htonl(mask); diff --git a/msgheader.cpp b/msgheader.cpp index c482f56..b551d32 100644 --- a/msgheader.cpp +++ b/msgheader.cpp @@ -44,6 +44,6 @@ std::expected MessageHeader::Decode(const std::string rawHead return {}; } -uint32_t MessageHeader::PacketSize() { +uint32_t MessageHeader::PayloadSize() { return pSize; } diff --git a/msgheader.hpp b/msgheader.hpp index a98a7c5..3b23610 100644 --- a/msgheader.hpp +++ b/msgheader.hpp @@ -12,6 +12,6 @@ public: MessageHeader(void); std::string Encode(void); std::expected Decode(const std::string buffer); - uint32_t PacketSize(void); + uint32_t PayloadSize(void); }; diff --git a/networkaux.cpp b/networkaux.cpp new file mode 100644 index 0000000..28d04b7 --- /dev/null +++ b/networkaux.cpp @@ -0,0 +1,81 @@ + +extern "C" { +#include +#include +} + +#include +#include +#include + +#include +#include + +std::expected netprefix(const std::string network) { + auto hostprefix = split(network, "/"); + if (hostprefix.size() < 2) { + return std::unexpected("Incorrect network definition"); + } + auto prefixRes = strtoint(hostprefix[1]); + if (!prefixRes) { + return std::unexpected("Incorrect tunnel network prefix:" + prefixRes.error()); + } + return prefixRes.value(); +} + +std::expected network(const std::string network) { + auto hostprefix = split(network, "/"); + if (hostprefix.size() < 2) { + return std::unexpected("Incorrect network definition"); + } + return hostprefix[0]; +} + + +std::expected nethost6(std::string network, int prefix, uint32_t num) { + struct in6_addr addr; + unsigned char mask[16] = {0}; + if (inet_pton(AF_INET6, network.data(), &addr) != 1) { + return std::unexpected(std::format("Invalid network address {}", network)); + } + for (int i = 0; i < prefix; i++) { + mask[i / 8] |= (1 << (7 - (i % 8))); + } + for (int i = 0; i < 16; i++) { + addr.s6_addr[i] &= mask[i]; + } + + uint64_t *host_part = (uint64_t *)&addr.s6_addr[8]; + uint64_t hostnum = be64toh(*host_part); + hostnum += num; + *host_part = htobe64(hostnum); + + char buffer[INET6_ADDRSTRLEN] = {'\0'}; + inet_ntop(AF_INET6, &addr, buffer, INET6_ADDRSTRLEN); + + return std::string(buffer); +} + + +std::expected nethost4(std::string network, int prefix, uint32_t num) { + struct in_addr inaddr; + if (inet_pton(AF_INET, network.data(), &inaddr) != 1) { + return std::unexpected(std::format("Invalid network address {}", network)); + } + uint32_t ip = ntohl(inaddr.s_addr); + uint32_t mask = (prefix == 0) ? 0 : (~0U << (32 - prefix)); + uint32_t fip = (ip & mask) + num; + struct in_addr ip_addr; + ip_addr.s_addr = htonl(fip); + return std::string(inet_ntoa(ip_addr)); +} + +std::expected nethost(std::string network, int prefix, uint32_t num) { + struct sockaddr_in sa; + if (inet_pton(AF_INET, network.data(), &(sa.sin_addr)) == 1) { + return nethost4(network, prefix, num); + } else if (inet_pton(AF_INET6, network.data(), &(sa.sin_addr)) == 1) { + return nethost6(network, prefix, num); + } + return std::unexpected(std::format("Unknown network address {}", network)); +} diff --git a/networkaux.hpp b/networkaux.hpp new file mode 100644 index 0000000..4de6f15 --- /dev/null +++ b/networkaux.hpp @@ -0,0 +1,11 @@ + +#ifndef NETWORKAUX_HPP + +#include +#include + +std::expected nethost(std::string network, int prefix, uint32_t num); +std::expected netprefix(const std::string network); +std::expected network(const std::string network); + +#endif diff --git a/sockhand.cpp b/sockhand.cpp index 4cf79c3..ce92e3f 100644 --- a/sockhand.cpp +++ b/sockhand.cpp @@ -19,29 +19,68 @@ extern "C" { #include +const std::string internetPkgMsg = "internetPkg"; +const std::string tunAddressMsg = "tunAddress"; +const std::string Msg = "localRoute"; + + using namespace std::chrono_literals; -void SocketHandler::Handle(int newsock) { +void SocketHandler::Handle(int newsock, std::string laddr, std::string raddr, int prefix) { sock = newsock; - - auto createRes = interface.Create(std::format("uxsrv{}", sock)); + auto interfaceName = std::format("uxsrv{}", sock); + auto createRes = interface.Create(interfaceName); if (!createRes) { - uxlogger.Log(createRes.error()); + uxlogger.Error(createRes.error()); + return; + } + uxlogger.Debug(std::format("Set local ip address {}/{} for {}", laddr, prefix, interfaceName)); + auto setAddrRes = interface.SetIP4Address(laddr); + if (!setAddrRes) { + uxlogger.Error(setAddrRes.error()); + return; + } + auto setPrefixRes = interface.SetIP4Netmask(prefix); + if (!setPrefixRes) { + uxlogger.Error(setPrefixRes.error()); return; } auto upRes = interface.Up(); if (!createRes) { - uxlogger.Log(createRes.error()); + uxlogger.Error(createRes.error()); return; } - std::thread sendThr(&SocketHandler::SendMessages, this); - sendThr.detach(); - std::thread recvThr(&SocketHandler::RecvMessages, this); recvThr.detach(); +#if 1 + uxcontrol::AddressMessage addrMsg; + auto meta = addrMsg.mutable_meta(); + meta->set_kind(tunAddressMsg); + addrMsg.set_address(raddr); + addrMsg.set_prefix(prefix); + std::string rawMessage; + addrMsg.SerializeToString(&rawMessage); + + MessageHeader header(rawMessage.size()); + auto rawHeader = header.Encode(); + std::string rawPacket; + rawPacket.append(rawHeader); + rawPacket.append(rawMessage); + + int wsize; + if ((wsize = write(sock, rawPacket.data(), rawPacket.size())) < 0) { + int errnoCopy = errno; + std::string error = std::strerror(errnoCopy); + uxlogger.Log(std::format("Write message error: {}", error)); + return; + } +#endif + std::thread sendThr(&SocketHandler::SendMessages, this); + sendThr.detach(); + done.acquire(); uxlogger.Log("Handler done"); } @@ -60,7 +99,7 @@ void SocketHandler::SendMessages(void) { break; } } - std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::seconds(30)); } done.release(); uxlogger.Log("Send messages done"); @@ -86,7 +125,7 @@ void SocketHandler::RecvMessages(void) { uxlogger.Log(std::format("Decode header error: {}", decodeRes.error())); break; } - auto pSize = header.PacketSize(); + auto pSize = header.PayloadSize(); if (pSize > 0) { std::string rawMessage(pSize, 0); if ((rsize = recv(sock, rawMessage.data(), rawMessage.size(), MSG_WAITALL)) < 0) { diff --git a/sockhand.hpp b/sockhand.hpp index 63557c5..5f66bab 100644 --- a/sockhand.hpp +++ b/sockhand.hpp @@ -9,6 +9,11 @@ #include +extern const std::string internetPkgMsg; +extern const std::string tunAddressMsg; +extern const std::string localRouteMsg; + + class SocketHandler { private: int sock; @@ -16,7 +21,7 @@ private: std::binary_semaphore done{0}; Interface interface; public: - void Handle(int newsock); + void Handle(int newsock, std::string laddr, std::string raddr, int prefix); void RecvMessages(void); void SendMessages(void); }; diff --git a/srvconfig.cpp b/srvconfig.cpp new file mode 100644 index 0000000..ed809a8 --- /dev/null +++ b/srvconfig.cpp @@ -0,0 +1,97 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +int ServConfig::Listenport(void) { + return listenport; +} + +std::vector ServConfig::Localnets(void) { + return localnets; +} + +std::string ServConfig::Tunnelnet(void) { + return tunnelnet; +} + +std::expected ServConfig::Read(std::string filename) { + std::ifstream file; + file.open(filename); + if (file.fail()) { + auto state = file.rdstate(); + if (state & std::ios_base::badbit) { + return std::unexpected("Read/writing error on i/o operation"); + } else if (state & std::ios_base::failbit) { + return std::unexpected("Logical error on i/o operation"); + } + } + + std::string line; + while (std::getline(file, line)) { + auto tokens = split(line, "#;"); + auto keyval = trim(tokens[0]); + if (keyval.size() == 0) continue; + tokens = split(keyval, "="); + if (tokens.size() < 2) continue; + auto key = trim(tokens[0]); + auto val = trim(tokens[1]); + kvmap[key] = val; + if (key == "localnet") { + localnets.push_back(val); + } else if (key == "tunnelnet") { + tunnelnet = val; + } else if (key == "listenport") { + auto convRes = strtoint(val); + if (!convRes) { + auto msg = std::format("listenport: {}", convRes.error()); + return std::unexpected(msg); + } + listenport = convRes.value(); + } + } + file.close(); + return {}; +} + +std::expected ServConfig::Validate(void) { + if (tunnelnet.size() == 0) { + return std::unexpected("Empty tunnel network"); + } + if (listenport == 0) { + return std::unexpected("Zero listen port"); + } + auto netprefixRes = netprefix(tunnelnet); + if (!netprefixRes) { + return std::unexpected("Incorrect tunnel network:" + netprefixRes.error()); + } + auto networkRes = network(tunnelnet); + if (!networkRes) { + return std::unexpected("Incorrect tunnel network:" + networkRes.error()); + } + for (const auto& val : localnets) { + auto netprefixRes = netprefix(val); + if (!netprefixRes) { + return std::unexpected("Incorrect local network " + val + ":" + netprefixRes.error()); + } + auto networkRes = network(val); + if (!networkRes) { + return std::unexpected("Incorrect local network " + val + ":" + networkRes.error()); + } + } + return {}; +} diff --git a/srvconfig.hpp b/srvconfig.hpp new file mode 100644 index 0000000..0771864 --- /dev/null +++ b/srvconfig.hpp @@ -0,0 +1,24 @@ + +#ifndef SRVCONFIG_HPP +#define SRVCONFIG_HPP + +#include +#include +#include +#include + +class ServConfig { +private: + std::map kvmap; + std::vector localnets; + std::string tunnelnet; + int listenport; +public: + std::expected Read(std::string filename); + int Listenport(void); + std::string Tunnelnet(void); + std::vector Localnets(void); + std::expected Validate(void); +}; + +#endif diff --git a/stringaux.cpp b/stringaux.cpp new file mode 100644 index 0000000..2683648 --- /dev/null +++ b/stringaux.cpp @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include +#include + +std::vector split(std::string s, std::string delimiters) { + std::vector tokens; + size_t last = 0, next = 0; + while ((next = s.find_first_of(delimiters, last)) != std::string::npos) { + if (next != last) tokens.push_back(s.substr(last, next - last)); + last = next + 1; + } + if (last < s.length()) tokens.push_back(s.substr(last)); + return tokens; +} + +std::string trim(std::string& source) { + auto line = source; + std::string whitespaces(" \t\n\r\f\v"); + line.erase(0, line.find_first_not_of(whitespaces)); + line.erase(line.find_last_not_of(whitespaces) + 1); + return line; +} + +std::expected strtoint (std::string source) { + std::size_t pos{}; + int res; + try { + res = std::stoi(source, &pos); + } catch (std::invalid_argument const& ex) { + return std::unexpected(std::format("invalid argument:{}", ex.what())); + } catch (std::out_of_range const& ex) { + return std::unexpected(std::format("out of range", ex.what())); + } + return res; +} diff --git a/stringaux.hpp b/stringaux.hpp new file mode 100644 index 0000000..2005016 --- /dev/null +++ b/stringaux.hpp @@ -0,0 +1,13 @@ + +#ifndef STRINGAUX_HPP +#define STRINGAUX_HPP + +#include +#include +#include + +std::vector split(std::string s, std::string delimiters); +std::string trim(std::string& source); +std::expected strtoint (std::string source); + +#endif diff --git a/tservice.cpp b/tservice.cpp index 179717b..506d005 100644 --- a/tservice.cpp +++ b/tservice.cpp @@ -11,18 +11,21 @@ extern "C" { #include #include +#include using namespace std::chrono_literals; -TCPService::TCPService(int svcport) { - port = svcport; +TunService::TunService(int svcport, std::string itunnelnet, std::vector ilocalnets) { + listenport = svcport; + tunnelnet = itunnelnet; + localnets = ilocalnets; } -TCPService::~TCPService() { - close(port); +TunService::~TunService() { + close(listenport); } -std::expected TCPService::Bind(void) { +std::expected TunService::Bind(void) { struct sockaddr_in address; int srvsock; if ((srvsock = socket(AF_INET, SOCK_STREAM, 0)) == 0) { @@ -38,7 +41,7 @@ std::expected TCPService::Bind(void) { } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; - address.sin_port = htons(port); + address.sin_port = htons(listenport); if (bind(srvsock, (struct sockaddr *)&address, sizeof(address)) < 0) { int errnocopy = errno; std::string error = std::strerror(errnocopy); @@ -53,7 +56,7 @@ std::expected TCPService::Bind(void) { return {}; } -std::expected TCPService::Listen(void) { +std::expected TunService::Listen(void) { struct sockaddr_in address; int addrlen = sizeof(address); int newsock = 0; @@ -63,18 +66,42 @@ std::expected TCPService::Listen(void) { std::string error = std::strerror(errnocopy); return std::unexpected("Accept error: " + error); } - std::jthread t(&TCPService::Handle, this, newsock); + + std::jthread t(&TunService::Handle, this, newsock); t.detach(); } return {}; } -void TCPService::Handle(int sock) { - uxlogger.Log("Start socker handler"); +void TunService::Handle(int sock) { + auto prefixRes = netprefix(tunnelnet); + if (!prefixRes) { + uxlogger.Error(prefixRes.error()); + return; + } + auto networkRes = network(tunnelnet); + if (!networkRes) { + uxlogger.Error(networkRes.error()); + return; + } + auto localaddrRes = nethost(networkRes.value(), prefixRes.value(), sock); + if (!networkRes) { + uxlogger.Error(networkRes.error()); + return; + } + auto remoteaddrRes = nethost(networkRes.value(), prefixRes.value(), sock + 1); + if (!remoteaddrRes) { + uxlogger.Error(remoteaddrRes.error()); + return; + } + uxlogger.Debug("Start socker handler"); SocketHandler handler; - handler.Handle(sock); - uxlogger.Log("Stop socker handler"); + std::string laddr = localaddrRes.value(); + std::string raddr = remoteaddrRes.value(); + auto prefix = prefixRes.value(); + handler.Handle(sock, laddr, raddr, prefix); + uxlogger.Debug("Stop socker handler"); close(sock); } diff --git a/tservice.hpp b/tservice.hpp index 9ce83f7..db9ec26 100644 --- a/tservice.hpp +++ b/tservice.hpp @@ -4,19 +4,22 @@ #include #include +#include #include -class TCPService { +class TunService { private: - int port; + std::string tunnelnet; + std::vector localnets; + int listenport; int sock; public: - explicit TCPService(int port); + explicit TunService(int port, std::string tunnelnet, std::vector localnets); std::expected Bind(void); std::expected Listen(void); void Handle(int sock); - ~TCPService(); + ~TunService(); }; #endif diff --git a/uxclient.cpp b/uxclient.cpp index b66f326..18c8df5 100644 --- a/uxclient.cpp +++ b/uxclient.cpp @@ -86,6 +86,7 @@ void UxClient::RecvMessages(void) { std::string rawHeader(msgHeaderSize, 0); if ((rsize = recv(sock, rawHeader.data(), rawHeader.size(), MSG_WAITALL)) < 0) { int errnoCopy = errno; + uxlogger.Log(std::format("Read0 header error: {}", errno)); std::string error = std::strerror(errnoCopy); uxlogger.Log(std::format("Read header error: {}", error)); break; @@ -99,7 +100,7 @@ void UxClient::RecvMessages(void) { if (!decodeRes) { uxlogger.Log(std::format("Decode header error: {}", decodeRes.error())); } - auto pSize = header.PacketSize(); + auto pSize = header.PayloadSize(); if (pSize > 0) { std::string rawMessage(pSize, 0); if ((rsize = recv(sock, rawMessage.data(), rawMessage.size(), MSG_WAITALL)) < 0) { @@ -109,6 +110,7 @@ void UxClient::RecvMessages(void) { break; } } + uxlogger.Log(std::format("Receive message with size {}", pSize)); } done.release(); @@ -117,6 +119,9 @@ void UxClient::RecvMessages(void) { void UxClient::SendMessages(void) { while (true) { + std::this_thread::sleep_for(std::chrono::seconds(10)); + continue; + auto readRes = interface.Read(); if (!readRes) { uxlogger.Log(std::format("Read packet error: {}", readRes.error())); @@ -133,6 +138,7 @@ void UxClient::SendMessages(void) { MessageHeader header(rawMessage.size()); auto rawHeader = header.Encode(); + int wsize = 0; if ((wsize = send(sock, rawHeader.data(), rawHeader.size(), 0)) < 0) { int errnoCopy = errno; diff --git a/uxcontrol.pb.cc b/uxcontrol.pb.cc index aad662c..da1637d 100644 --- a/uxcontrol.pb.cc +++ b/uxcontrol.pb.cc @@ -65,7 +65,7 @@ PROTOBUF_CONSTEXPR AddressMessage::AddressMessage( ::_pbi::ConstantInitialized): _impl_{ /*decltype(_impl_.address_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}} , /*decltype(_impl_.meta_)*/nullptr - , /*decltype(_impl_.prefix_)*/uint64_t{0u} + , /*decltype(_impl_.prefix_)*/0u , /*decltype(_impl_._cached_size_)*/{}} {} struct AddressMessageDefaultTypeInternal { PROTOBUF_CONSTEXPR AddressMessageDefaultTypeInternal() @@ -185,7 +185,7 @@ const char descriptor_table_protodef_uxcontrol_2eproto[] PROTOBUF_SECTION_VARIAB "Message\022#\n\004meta\030\001 \001(\0132\025.uxcontrol.MetaHe" "ader\022\017\n\007payload\030\002 \001(\014\"V\n\016AddressMessage\022" "#\n\004meta\030\001 \001(\0132\025.uxcontrol.MetaHeader\022\017\n\007" - "address\030\002 \001(\t\022\016\n\006prefix\030\003 \001(\004\"T\n\014RouteMe" + "address\030\002 \001(\t\022\016\n\006prefix\030\003 \001(\r\"T\n\014RouteMe" "ssage\022#\n\004meta\030\001 \001(\0132\025.uxcontrol.MetaHead" "er\022\017\n\007address\030\002 \001(\t\022\016\n\006prefix\030\003 \001(\004\"D\n\014H" "elloMessage\022#\n\004meta\030\001 \001(\0132\025.uxcontrol.Me" @@ -893,7 +893,7 @@ inline void AddressMessage::SharedCtor( new (&_impl_) Impl_{ decltype(_impl_.address_){} , decltype(_impl_.meta_){nullptr} - , decltype(_impl_.prefix_){uint64_t{0u}} + , decltype(_impl_.prefix_){0u} , /*decltype(_impl_._cached_size_)*/{} }; _impl_.address_.InitDefault(); @@ -932,7 +932,7 @@ void AddressMessage::Clear() { delete _impl_.meta_; } _impl_.meta_ = nullptr; - _impl_.prefix_ = uint64_t{0u}; + _impl_.prefix_ = 0u; _internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(); } @@ -960,10 +960,10 @@ const char* AddressMessage::_InternalParse(const char* ptr, ::_pbi::ParseContext } else goto handle_unusual; continue; - // uint64 prefix = 3; + // uint32 prefix = 3; case 3: if (PROTOBUF_PREDICT_TRUE(static_cast(tag) == 24)) { - _impl_.prefix_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint64(&ptr); + _impl_.prefix_ = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr); CHK_(ptr); } else goto handle_unusual; @@ -1014,10 +1014,10 @@ uint8_t* AddressMessage::_InternalSerialize( 2, this->_internal_address(), target); } - // uint64 prefix = 3; + // uint32 prefix = 3; if (this->_internal_prefix() != 0) { target = stream->EnsureSpace(target); - target = ::_pbi::WireFormatLite::WriteUInt64ToArray(3, this->_internal_prefix(), target); + target = ::_pbi::WireFormatLite::WriteUInt32ToArray(3, this->_internal_prefix(), target); } if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) { @@ -1050,9 +1050,9 @@ size_t AddressMessage::ByteSizeLong() const { *_impl_.meta_); } - // uint64 prefix = 3; + // uint32 prefix = 3; if (this->_internal_prefix() != 0) { - total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_prefix()); + total_size += ::_pbi::WireFormatLite::UInt32SizePlusOne(this->_internal_prefix()); } return MaybeComputeUnknownFieldsSize(total_size, &_impl_._cached_size_); diff --git a/uxcontrol.pb.h b/uxcontrol.pb.h index f047b38..2e17874 100644 --- a/uxcontrol.pb.h +++ b/uxcontrol.pb.h @@ -716,13 +716,13 @@ class AddressMessage final : ::uxcontrol::MetaHeader* meta); ::uxcontrol::MetaHeader* unsafe_arena_release_meta(); - // uint64 prefix = 3; + // uint32 prefix = 3; void clear_prefix(); - uint64_t prefix() const; - void set_prefix(uint64_t value); + uint32_t prefix() const; + void set_prefix(uint32_t value); private: - uint64_t _internal_prefix() const; - void _internal_set_prefix(uint64_t value); + uint32_t _internal_prefix() const; + void _internal_set_prefix(uint32_t value); public: // @@protoc_insertion_point(class_scope:uxcontrol.AddressMessage) @@ -735,7 +735,7 @@ class AddressMessage final : struct Impl_ { ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr address_; ::uxcontrol::MetaHeader* meta_; - uint64_t prefix_; + uint32_t prefix_; mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_; }; union { Impl_ _impl_; }; @@ -1541,22 +1541,22 @@ inline void AddressMessage::set_allocated_address(std::string* address) { // @@protoc_insertion_point(field_set_allocated:uxcontrol.AddressMessage.address) } -// uint64 prefix = 3; +// uint32 prefix = 3; inline void AddressMessage::clear_prefix() { - _impl_.prefix_ = uint64_t{0u}; + _impl_.prefix_ = 0u; } -inline uint64_t AddressMessage::_internal_prefix() const { +inline uint32_t AddressMessage::_internal_prefix() const { return _impl_.prefix_; } -inline uint64_t AddressMessage::prefix() const { +inline uint32_t AddressMessage::prefix() const { // @@protoc_insertion_point(field_get:uxcontrol.AddressMessage.prefix) return _internal_prefix(); } -inline void AddressMessage::_internal_set_prefix(uint64_t value) { +inline void AddressMessage::_internal_set_prefix(uint32_t value) { _impl_.prefix_ = value; } -inline void AddressMessage::set_prefix(uint64_t value) { +inline void AddressMessage::set_prefix(uint32_t value) { _internal_set_prefix(value); // @@protoc_insertion_point(field_set:uxcontrol.AddressMessage.prefix) } diff --git a/uxcontrol.proto b/uxcontrol.proto index 2c48eb1..740e264 100644 --- a/uxcontrol.proto +++ b/uxcontrol.proto @@ -21,7 +21,7 @@ message PacketMessage { message AddressMessage { MetaHeader meta = 1; string address = 2; - uint64 prefix = 3; + uint32 prefix = 3; } message RouteMessage { diff --git a/uxlogger.cpp b/uxlogger.cpp index b6825c1..2e1573f 100644 --- a/uxlogger.cpp +++ b/uxlogger.cpp @@ -22,6 +22,7 @@ UxLogger::UxLogger(const std::string ilabel) { UxLogger::UxLogger(void) { label = "global"; } + void UxLogger::Log(const std::string& message) { auto now = std::chrono::system_clock::now(); std::chrono::zoned_time localnow{std::chrono::current_zone(), now}; @@ -30,3 +31,27 @@ void UxLogger::Log(const std::string& message) { std::cout << std::format("{} {} {}\n", timenow, label, message); } +void UxLogger::Debug(const std::string& message) { + LogLevel("debug", message); +} + +void UxLogger::Info(const std::string& message) { + LogLevel("info", message); +} + +void UxLogger::Warning(const std::string& message) { + LogLevel("warning", message); +} + +void UxLogger::Error(const std::string& message) { + LogLevel("error", message); +} + +void UxLogger::LogLevel(const std::string level, const std::string& message) { + auto now = std::chrono::system_clock::now(); + std::chrono::zoned_time localnow{std::chrono::current_zone(), now}; + std::string timenow = std::format("{:%Y-%m-%dT%H:%M:%OS%Z}", localnow); + std::lock_guard lock(mtx); + std::cout << std::format("{} {} {} {}\n", timenow, level, label, message); +} + diff --git a/uxlogger.hpp b/uxlogger.hpp index 41c5dd6..b6cf059 100644 --- a/uxlogger.hpp +++ b/uxlogger.hpp @@ -11,12 +11,18 @@ class UxLogger { private: std::string label; + void LogLevel(const std::string level, const std::string& message); public: UxLogger(std::string ilabel); UxLogger(); void Log(const std::string& message); + void Debug(const std::string& message); + void Info(const std::string& message); + void Warning(const std::string& message); + void Error(const std::string& message); }; + extern UxLogger uxlogger; #endif diff --git a/works/config/config.cpp b/works/config/config.cpp new file mode 100644 index 0000000..85e3abe --- /dev/null +++ b/works/config/config.cpp @@ -0,0 +1,126 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +std::vector split(std::string s, std::string delimiters) { + std::vector tokens; + size_t last = 0, next = 0; + while ((next = s.find_first_of(delimiters, last)) != std::string::npos) { + if (next != last) tokens.push_back(s.substr(last, next - last)); + last = next + 1; + } + if (last < s.length()) tokens.push_back(s.substr(last)); + return tokens; +} + +std::string trim(std::string& source) { + auto line = source; + std::string whitespaces(" \t\n\r\f\v"); + line.erase(0, line.find_first_not_of(whitespaces)); + line.erase(line.find_last_not_of(whitespaces) + 1); + return line; +} + +std::expected str2int (std::string source) { + std::size_t pos{}; + int res; + try { + res = std::stoi(source, &pos); + } + catch (std::invalid_argument const& ex) { + return std::unexpected(std::format("invalid argument:{}", ex.what())); + } + catch (std::out_of_range const& ex) { + return std::unexpected(std::format("out of range", ex.what())); + } + return res; +} + +class Registry { +private: + std::map kvmap; + std::vector localnets; + std::string tunnelnet; + int listenport; +public: + std::expected Read(std::string filename); + int Listenport(void); + std::string Tunnelnet(void); + std::vector Localnets(void); + +}; + +int Registry::Listenport(void){ + return listenport; +} + +std::vector Registry::Localnets(void){ + return localnets; +} + +std::string Registry::Tunnelnet(void){ + return tunnelnet; +} + +std::expected Registry::Read(std::string filename) { + std::ifstream file; + file.open(filename); + if (file.fail()) { + auto state = file.rdstate(); + if (state & std::ios_base::badbit) { + return std::unexpected("Read/writing error on i/o operation"); + } else if (state & std::ios_base::failbit) { + return std::unexpected("Logical error on i/o operation"); + } + } + + std::string line; + while (std::getline(file, line)) { + auto tokens = split(line, "#;"); + auto keyval = trim(tokens[0]); + if (keyval.size() == 0) continue; + tokens = split(keyval, "="); + if (tokens.size() < 2) continue; + auto key = trim(tokens[0]); + auto val = trim(tokens[1]); + kvmap[key] = val; + if (key == "localnet") { + localnets.push_back(val); + } else if (key == "tunnelnet") { + tunnelnet = val; + } else if (key == "listenport") { + auto convRes = str2int(val); + if (!convRes) { + auto msg = std::format("listenport: {}", convRes.error()); + return std::unexpected(msg); + } + listenport = convRes.value(); + } + } + file.close(); + //for (auto const& [key, val] : kvmap) { + // std::cout << key << ":" << val << std::endl; + //} + return {}; +} + +int main() { + Registry config; + auto openRes = config.Read("example.conf"); + if (!openRes) { + std::cerr << openRes.error() << std::endl; + return 1; + } + return 0; +} diff --git a/works/config/example.conf b/works/config/example.conf new file mode 100644 index 0000000..fc2b773 --- /dev/null +++ b/works/config/example.conf @@ -0,0 +1,5 @@ +# foo + # foobare + localnet == 10.1.1.0/24 #qwert + localnet == 10.1.2.0/24 #qwert + ddd = diff --git a/works/iprange.cpp b/works/iprange.cpp index 12a5601..37a402f 100644 --- a/works/iprange.cpp +++ b/works/iprange.cpp @@ -10,7 +10,7 @@ extern "C" { #include #include -std::expected network6(std::string network, int prefix) { +std::expected nethost6(std::string network, int prefix, uint32_t num) { struct in6_addr addr; unsigned char mask[16] = {0}; if (inet_pton(AF_INET6, network.data(), &addr) != 1) { @@ -25,7 +25,7 @@ std::expected network6(std::string network, int prefix uint64_t *host_part = (uint64_t *)&addr.s6_addr[8]; uint64_t hostnum = be64toh(*host_part); - hostnum += 2; + hostnum += num; *host_part = htobe64(hostnum); char buffer[INET6_ADDRSTRLEN] = {'\0'}; @@ -35,29 +35,38 @@ std::expected network6(std::string network, int prefix } -std::expected network4(std::string network, int prefix) { +std::expected nethost4(std::string network, int prefix, uint32_t num) { struct in_addr inaddr; if (inet_pton(AF_INET, network.data(), &inaddr) != 1) { return std::unexpected(std::format("Invalid network address {}", network)); } uint32_t ip = ntohl(inaddr.s_addr); uint32_t mask = (prefix == 0) ? 0 : (~0U << (32 - prefix)); - uint32_t fip = (ip & mask) + 1; + uint32_t fip = (ip & mask) + num; struct in_addr ip_addr; - ip_addr.s_addr = htonl(ip); - + ip_addr.s_addr = htonl(fip); return std::string(inet_ntoa(ip_addr)); } +std::expected nethost(std::string network, int prefix, uint32_t num) { + struct sockaddr_in sa; + if (inet_pton(AF_INET, network.data(), &(sa.sin_addr)) == 1) { + return nethost4(network, prefix, num); + } else if (inet_pton(AF_INET6, network.data(), &(sa.sin_addr)) == 1) { + return nethost6(network, prefix, num); + } + return std::unexpected(std::format("Unknown network address {}", network)); +} + int main() { - auto net4Res = network4("192.168.1.154", 26); + auto net4Res = nethost4("192.168.1.151", 24, 1); if (!net4Res) { std::cerr << net4Res.error() << std::endl; return 1; } std::cout << net4Res.value() << std::endl; - auto net6Res = network6("2001:db8:abcd:1234::0", 64); + auto net6Res = nethost6("2001:db8:abcd:1234::0", 64, 1); if (!net6Res) { std::cerr << net6Res.error() << std::endl; return 1;