More towards C++

This commit is contained in:
Friedrich Schöller 2017-05-12 00:13:50 +02:00
parent c9b07d96bc
commit 41f9ed5ef4
16 changed files with 178 additions and 172 deletions

View File

@ -23,10 +23,9 @@
#include <arpa/inet.h> #include <arpa/inet.h>
Auth::Auth(const char *passphrase) Auth::Auth(const std::string &passphrase)
{ : passphrase(passphrase)
this->passphrase = passphrase; { }
}
Auth::Response Auth::getResponse(const Challenge &challenge) const Auth::Response Auth::getResponse(const Challenge &challenge) const
{ {
@ -34,7 +33,7 @@ Auth::Response Auth::getResponse(const Challenge &challenge) const
Response response; Response response;
hasher << passphrase.c_str(); hasher << passphrase.data();
hasher.Input(&challenge[0], challenge.size()); hasher.Input(&challenge[0], challenge.size());
hasher.Result((unsigned int *)response.data); hasher.Result((unsigned int *)response.data);

View File

@ -36,7 +36,7 @@ public:
bool operator==(const Response &other) const { return memcmp(this, &other, sizeof(Response)) == 0; } bool operator==(const Response &other) const { return memcmp(this, &other, sizeof(Response)) == 0; }
}; };
Auth(const char *passphrase); Auth(const std::string &passphrase);
Challenge generateChallenge(int length) const; Challenge generateChallenge(int length) const;
Response getResponse(const Challenge &challenge) const; Response getResponse(const Challenge &challenge) const;

View File

@ -28,14 +28,15 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <syslog.h> #include <syslog.h>
using namespace std; using std::vector;
using std::string;
const Worker::TunnelHeader::Magic Client::magic("hanc"); const Worker::TunnelHeader::Magic Client::magic("hanc");
Client::Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, Client::Client(int tunnelMtu, const string *deviceName, uint32_t serverIp,
int maxPolls, const char *passphrase, uid_t uid, gid_t gid, int maxPolls, const string &passphrase, uid_t uid, gid_t gid,
bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp) bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp)
: Worker(tunnelMtu, deviceName, false, uid, gid), auth(passphrase) : Worker(tunnelMtu, deviceName, false, uid, gid), auth(passphrase)
{ {
this->serverIp = serverIp; this->serverIp = serverIp;
this->clientIp = INADDR_NONE; this->clientIp = INADDR_NONE;
@ -137,7 +138,7 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
clientIp = ip; clientIp = ip;
desiredIp = ip; desiredIp = ip;
tun->setIp(ip, (ip & 0xffffff00) + 1); tun.setIp(ip, (ip & 0xffffff00) + 1);
} }
state = STATE_ESTABLISHED; state = STATE_ESTABLISHED;
@ -160,6 +161,8 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
return true; return true;
} }
break; break;
default:
break;
} }
syslog(LOG_DEBUG, "invalid packet type: %d, state: %d", header.type, state); syslog(LOG_DEBUG, "invalid packet type: %d, state: %d", header.type, state);
@ -167,7 +170,7 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
return true; return true;
} }
void Client::sendEchoToServer(int type, int dataLength) void Client::sendEchoToServer(Worker::TunnelHeader::Type type, int dataLength)
{ {
if (maxPolls == 0 && state == STATE_ESTABLISHED) if (maxPolls == 0 && state == STATE_ESTABLISHED)
setTimeout(KEEP_ALIVE_INTERVAL); setTimeout(KEEP_ALIVE_INTERVAL);

View File

@ -27,9 +27,10 @@
class Client : public Worker class Client : public Worker
{ {
public: public:
Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, Client(int tunnelMtu, const std::string *deviceName, uint32_t serverIp,
int maxPolls, const char *passphrase, uid_t uid, gid_t gid, int maxPolls, const std::string &passphrase, uid_t uid, gid_t gid,
bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp); bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp);
virtual ~Client(); virtual ~Client();
@ -53,7 +54,7 @@ protected:
void startPolling(); void startPolling();
void sendEchoToServer(int type, int dataLength); void sendEchoToServer(Worker::TunnelHeader::Type type, int dataLength);
void sendChallengeResponse(int dataLength); void sendChallengeResponse(int dataLength);
void sendConnectionRequest(); void sendConnectionRequest();

View File

@ -42,16 +42,13 @@ Echo::Echo(int maxPayloadSize)
throw Exception("creating icmp socket", true); throw Exception("creating icmp socket", true);
bufferSize = maxPayloadSize + headerSize(); bufferSize = maxPayloadSize + headerSize();
sendBuffer = new char[bufferSize]; sendBuffer.resize(bufferSize);
receiveBuffer = new char[bufferSize]; receiveBuffer.resize(bufferSize);
} }
Echo::~Echo() Echo::~Echo()
{ {
close(fd); close(fd);
delete[] sendBuffer;
delete[] receiveBuffer;
} }
int Echo::headerSize() int Echo::headerSize()
@ -68,15 +65,15 @@ void Echo::send(int payloadLength, uint32_t realIp, bool reply, uint16_t id, uin
if (payloadLength + sizeof(IpHeader) + sizeof(EchoHeader) > bufferSize) if (payloadLength + sizeof(IpHeader) + sizeof(EchoHeader) > bufferSize)
throw Exception("packet too big"); throw Exception("packet too big");
EchoHeader *header = (EchoHeader *)(sendBuffer + sizeof(IpHeader)); EchoHeader *header = (EchoHeader *)(sendBuffer.data() + sizeof(IpHeader));
header->type = reply ? 0: 8; header->type = reply ? 0: 8;
header->code = 0; header->code = 0;
header->id = htons(id); header->id = htons(id);
header->seq = htons(seq); header->seq = htons(seq);
header->chksum = 0; header->chksum = 0;
header->chksum = icmpChecksum(sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader)); header->chksum = icmpChecksum(sendBuffer.data() + sizeof(IpHeader), payloadLength + sizeof(EchoHeader));
int result = sendto(fd, sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in)); int result = sendto(fd, sendBuffer.data() + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
if (result == -1) if (result == -1)
syslog(LOG_ERR, "error sending icmp packet: %s", strerror(errno)); syslog(LOG_ERR, "error sending icmp packet: %s", strerror(errno));
} }
@ -86,7 +83,7 @@ int Echo::receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq)
struct sockaddr_in source; struct sockaddr_in source;
int source_addr_len = sizeof(struct sockaddr_in); int source_addr_len = sizeof(struct sockaddr_in);
int dataLength = recvfrom(fd, receiveBuffer, bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len); int dataLength = recvfrom(fd, receiveBuffer.data(), bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
if (dataLength == -1) if (dataLength == -1)
{ {
syslog(LOG_ERR, "error receiving icmp packet: %s", strerror(errno)); syslog(LOG_ERR, "error receiving icmp packet: %s", strerror(errno));
@ -96,7 +93,7 @@ int Echo::receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq)
if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader)) if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader))
return -1; return -1;
EchoHeader *header = (EchoHeader *)(receiveBuffer + sizeof(IpHeader)); EchoHeader *header = (EchoHeader *)(receiveBuffer.data() + sizeof(IpHeader));
if ((header->type != 0 && header->type != 8) || header->code != 0) if ((header->type != 0 && header->type != 8) || header->code != 0)
return -1; return -1;
@ -122,3 +119,13 @@ uint16_t Echo::icmpChecksum(const char *data, int length)
sum += (sum >> 16); sum += (sum >> 16);
return ~sum; return ~sum;
} }
char *Echo::sendPayloadBuffer()
{
return sendBuffer.data() + headerSize();
}
char *Echo::receivePayloadBuffer()
{
return receiveBuffer.data() + headerSize();
}

View File

@ -21,6 +21,7 @@
#define ECHO_H #define ECHO_H
#include <string> #include <string>
#include <vector>
#include <stdint.h> #include <stdint.h>
class Echo class Echo
@ -34,8 +35,8 @@ public:
void send(int payloadLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq); void send(int payloadLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
int receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq); int receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq);
char *sendPayloadBuffer() { return sendBuffer + headerSize(); } char *sendPayloadBuffer();
char *receivePayloadBuffer() { return receiveBuffer + headerSize(); } char *receivePayloadBuffer();
static int headerSize(); static int headerSize();
protected: protected:
@ -52,7 +53,8 @@ protected:
int fd; int fd;
int bufferSize; int bufferSize;
char *sendBuffer, *receiveBuffer; std::vector<char> sendBuffer;
std::vector<char> receiveBuffer;
}; };
#endif #endif

View File

@ -23,22 +23,17 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
using namespace std; using std::string;
Exception::Exception(const char *msg) Exception::Exception(const string &msg)
{ {
this->msg = msg; this->msg = msg;
} }
Exception::Exception(const string msg) Exception::Exception(const string &msg, bool appendSystemError)
{
this->msg = msg;
}
Exception::Exception(const char *msg, bool appendSystemError)
{ {
if (appendSystemError) if (appendSystemError)
this->msg = string(msg) + ": " + strerror(errno); this->msg = msg + ": " + strerror(errno);
else else
this->msg = msg; this->msg = msg;
} }

View File

@ -22,11 +22,10 @@
class Exception class Exception
{ {
public: public:
Exception(const char *msg); Exception(const std::string &msg);
Exception(const std::string msg); Exception(const std::string &msg, bool appendSystemError);
Exception(const char *msg, bool appendSystemError);
const char *errorMessage() const { return msg.c_str(); } const std::string &errorMessage() const { return msg; }
protected: protected:
std::string msg; std::string msg;
}; };

View File

@ -21,7 +21,7 @@
#include "server.h" #include "server.h"
#include "exception.h" #include "exception.h"
#include <stdio.h> #include <iostream>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h> #include <sys/types.h>
@ -35,11 +35,14 @@
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <signal.h> #include <signal.h>
#include <memory>
#ifndef AI_V4MAPPED // Not supported on OpenBSD 6.0 #ifndef AI_V4MAPPED // Not supported on OpenBSD 6.0
#define AI_V4MAPPED 0 #define AI_V4MAPPED 0
#endif #endif
using std::string;
static Worker *worker = NULL; static Worker *worker = NULL;
static void sig_term_handler(int) static void sig_term_handler(int)
@ -58,7 +61,7 @@ static void sig_int_handler(int)
static void usage() static void usage()
{ {
printf( std::cerr <<
"Hans - IP over ICMP version 1.0\n\n" "Hans - IP over ICMP version 1.0\n\n"
"RUN AS CLIENT\n" "RUN AS CLIENT\n"
" hans -c server [-fv] [-p passphrase] [-u user] [-d tun_device]\n" " hans -c server [-fv] [-p passphrase] [-u user] [-d tun_device]\n"
@ -86,16 +89,15 @@ static void usage()
" -q Change echo sequence number on every echo request. May help with\n" " -q Change echo sequence number on every echo request. May help with\n"
" buggy routers. May impact performance with others.\n" " buggy routers. May impact performance with others.\n"
" -f Run in foreground.\n" " -f Run in foreground.\n"
" -v Print debug information.\n" " -v Print debug information.\n";
);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const char *serverName; string serverName;
const char *userName = NULL; string userName;
const char *password = ""; string passphrase;
const char *device = NULL; string device;
bool isServer = false; bool isServer = false;
bool isClient = false; bool isClient = false;
bool foreground = false; bool foreground = false;
@ -126,7 +128,7 @@ int main(int argc, char *argv[])
device = optarg; device = optarg;
break; break;
case 'p': case 'p':
password = strdup(optarg); passphrase = optarg;
memset(optarg, 0, strlen(optarg)); memset(optarg, 0, strlen(optarg));
break; break;
case 'c': case 'c':
@ -137,7 +139,7 @@ int main(int argc, char *argv[])
isServer = true; isServer = true;
network = ntohl(inet_addr(optarg)); network = ntohl(inet_addr(optarg));
if (network == INADDR_NONE) if (network == INADDR_NONE)
printf("invalid network\n"); std::cerr << "invalid network\n";
break; break;
case 'm': case 'm':
mtu = atoi(optarg); mtu = atoi(optarg);
@ -170,8 +172,9 @@ int main(int argc, char *argv[])
if (mtu < 68) if (mtu < 68)
{ {
// RFC 791: Every internet module must be able to forward a datagram of 68 octets without further fragmentation. // RFC 791: Every internet module must be able to forward a datagram of
printf("mtu too small\n"); // 68 octets without further fragmentation.
std::cerr << "mtu too small\n";
return 1; return 1;
} }
@ -184,13 +187,13 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
if (userName != NULL) if (!userName.empty())
{ {
#ifdef WIN32 #ifdef WIN32
syslog(LOG_ERR, "dropping privileges is not supported on Windows"); syslog(LOG_ERR, "dropping privileges is not supported on Windows");
return 1; return 1;
#endif #endif
passwd *pw = getpwnam(userName); passwd *pw = getpwnam(userName.data());
if (pw != NULL) if (pw != NULL)
{ {
@ -214,7 +217,8 @@ int main(int argc, char *argv[])
{ {
if (isServer) if (isServer)
{ {
worker = new Server(mtu, device, password, network, answerPing, uid, gid, 5000); worker = new Server(mtu, device.empty() ? NULL : &device, passphrase,
network, answerPing, uid, gid, 5000);
} }
else else
{ {
@ -224,7 +228,7 @@ int main(int argc, char *argv[])
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
int err = getaddrinfo(serverName, NULL, &hints, &res); int err = getaddrinfo(serverName.data(), NULL, &hints, &res);
if (err) if (err)
{ {
syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(err)); syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(err));
@ -234,7 +238,9 @@ int main(int argc, char *argv[])
sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(res->ai_addr); sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(res->ai_addr);
uint32_t serverIp = sockaddr->sin_addr.s_addr; uint32_t serverIp = sockaddr->sin_addr.s_addr;
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq, clientIp); worker = new Client(mtu, device.empty() ? NULL : &device,
ntohl(serverIp), maxPolls, passphrase, uid, gid,
changeEchoId, changeEchoSeq, clientIp);
freeaddrinfo(res); freeaddrinfo(res);
} }
@ -249,7 +255,7 @@ int main(int argc, char *argv[])
} }
catch (Exception e) catch (Exception e)
{ {
syslog(LOG_ERR, "%s", e.errorMessage()); syslog(LOG_ERR, "%s", e.errorMessage().data());
delete worker; delete worker;
return 1; return 1;
} }

View File

@ -25,22 +25,25 @@
#include <string.h> #include <string.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <syslog.h> #include <syslog.h>
#include <stdio.h> #include <iostream>
using namespace std; using std::string;
using std::cout;
using std::endl;
#define FIRST_ASSIGNED_IP_OFFSET 100 #define FIRST_ASSIGNED_IP_OFFSET 100
const Worker::TunnelHeader::Magic Server::magic("hans"); const Worker::TunnelHeader::Magic Server::magic("hans");
Server::Server(int tunnelMtu, const char *deviceName, const char *passphrase, uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout) Server::Server(int tunnelMtu, const string *deviceName, const string &passphrase,
uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout)
: Worker(tunnelMtu, deviceName, answerEcho, uid, gid), auth(passphrase) : Worker(tunnelMtu, deviceName, answerEcho, uid, gid), auth(passphrase)
{ {
this->network = network & 0xffffff00; this->network = network & 0xffffff00;
this->pollTimeout = pollTimeout; this->pollTimeout = pollTimeout;
this->latestAssignedIpOffset = FIRST_ASSIGNED_IP_OFFSET - 1; this->latestAssignedIpOffset = FIRST_ASSIGNED_IP_OFFSET - 1;
tun->setIp(this->network + 1, this->network + 2); tun.setIp(this->network + 1, this->network + 2);
dropPrivileges(); dropPrivileges();
} }
@ -200,6 +203,8 @@ bool Server::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
break; break;
case TunnelHeader::TYPE_POLL: case TunnelHeader::TYPE_POLL:
return true; return true;
default:
break;
} }
syslog(LOG_DEBUG, "invalid packet from: %s, type: %d, state: %d", Utility::formatIp(realIp).c_str(), header.type, client->state); syslog(LOG_DEBUG, "invalid packet from: %s, type: %d, state: %d", Utility::formatIp(realIp).c_str(), header.type, client->state);
@ -248,7 +253,7 @@ void Server::pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq)
client->pollIds.push(ClientData::EchoId(echoId, echoSeq)); client->pollIds.push(ClientData::EchoId(echoId, echoSeq));
if (client->pollIds.size() > maxSavedPolls) if (client->pollIds.size() > maxSavedPolls)
client->pollIds.pop(); client->pollIds.pop();
DEBUG_ONLY(printf("poll -> %d\n", (int)client->pollIds.size())); DEBUG_ONLY(cout << "poll -> " << client->pollIds.size() << endl);
if (client->pendingPackets.size() > 0) if (client->pendingPackets.size() > 0)
{ {
@ -256,14 +261,14 @@ void Server::pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq)
memcpy(echoSendPayloadBuffer(), &packet.data[0], packet.data.size()); memcpy(echoSendPayloadBuffer(), &packet.data[0], packet.data.size());
client->pendingPackets.pop(); client->pendingPackets.pop();
DEBUG_ONLY(printf("pending packet: %d bytes\n", (int)packet.data.size())); DEBUG_ONLY(cout << "pending packet: " << packet.data.size() << " bytes\n");
sendEchoToClient(client, packet.type, packet.data.size()); sendEchoToClient(client, packet.type, packet.data.size());
} }
client->lastActivity = now; client->lastActivity = now;
} }
void Server::sendEchoToClient(ClientData *client, int type, int dataLength) void Server::sendEchoToClient(ClientData *client, TunnelHeader::Type type, int dataLength)
{ {
if (client->maxPolls == 0) if (client->maxPolls == 0)
{ {
@ -276,7 +281,7 @@ void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
ClientData::EchoId echoId = client->pollIds.front(); ClientData::EchoId echoId = client->pollIds.front();
client->pollIds.pop(); client->pollIds.pop();
DEBUG_ONLY(printf("sending -> %d\n", (int)client->pollIds.size())); DEBUG_ONLY(cout << "sending -> " << client->pollIds.size() << endl);
sendEcho(magic, type, dataLength, client->realIp, true, echoId.id, echoId.seq); sendEcho(magic, type, dataLength, client->realIp, true, echoId.id, echoId.seq);
return; return;
} }
@ -287,7 +292,7 @@ void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
syslog(LOG_WARNING, "packet dropped to %s", Utility::formatIp(client->tunnelIp).c_str()); syslog(LOG_WARNING, "packet dropped to %s", Utility::formatIp(client->tunnelIp).c_str());
} }
DEBUG_ONLY(printf("packet queued: %d bytes\n", dataLength)); DEBUG_ONLY(cout << "packet queued: " << dataLength << " bytes\n");
client->pendingPackets.push(Packet()); client->pendingPackets.push(Packet());
Packet &packet = client->pendingPackets.back(); Packet &packet = client->pendingPackets.back();

View File

@ -28,27 +28,27 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <set> #include <set>
#include <string>
class Server : public Worker class Server : public Worker
{ {
public: public:
Server(int tunnelMtu, const char *deviceName, const char *passphrase, uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout); Server(int tunnelMtu, const std::string *deviceName, const std::string &passphrase,
uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout);
virtual ~Server(); virtual ~Server();
// change some time:
// struct __attribute__ ((__packed__)) ClientConnectData
struct ClientConnectData struct ClientConnectData
{ {
uint8_t maxPolls; uint8_t maxPolls;
uint32_t desiredIp; uint32_t desiredIp;
}; };
static const Worker::TunnelHeader::Magic magic; static const TunnelHeader::Magic magic;
protected: protected:
struct Packet struct Packet
{ {
int type; TunnelHeader::Type type;
std::vector<char> data; std::vector<char> data;
}; };
@ -101,7 +101,7 @@ protected:
void checkChallenge(ClientData *client, int dataLength); void checkChallenge(ClientData *client, int dataLength);
void sendReset(ClientData *client); void sendReset(ClientData *client);
void sendEchoToClient(ClientData *client, int type, int dataLength); void sendEchoToClient(ClientData *client, TunnelHeader::Type type, int dataLength);
void pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq); void pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq);

View File

@ -30,6 +30,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <sstream>
#ifdef WIN32 #ifdef WIN32
#include <w32api/windows.h> #include <w32api/windows.h>
@ -37,7 +38,7 @@
typedef ip IpHeader; typedef ip IpHeader;
using namespace std; using std::string;
#ifdef WIN32 #ifdef WIN32
static void winsystem(char *cmd) static void winsystem(char *cmd)
@ -53,61 +54,61 @@ static void winsystem(char *cmd)
} }
#endif #endif
Tun::Tun(const char *device, int mtu) Tun::Tun(const string *device, int mtu)
{ {
char cmdline[512];
this->mtu = mtu; this->mtu = mtu;
if (device != NULL) if (device)
{ this->device = *device;
strncpy(this->device, device, VTUN_DEV_LEN);
this->device[VTUN_DEV_LEN-1] = 0; this->device.resize(VTUN_DEV_LEN);
} fd = tun_open(&this->device[0]);
else this->device.resize(strlen(this->device.data()));
this->device[0] = 0;
fd = tun_open(this->device);
if (fd == -1) if (fd == -1)
throw Exception(string("could not create tunnel device: ") + tun_last_error()); throw Exception(string("could not create tunnel device: ") + tun_last_error());
syslog(LOG_INFO, "opened tunnel device: %s", this->device); syslog(LOG_INFO, "opened tunnel device: %s", this->device.data());
std::stringstream cmdline;
#ifdef WIN32 #ifdef WIN32
snprintf(cmdline, sizeof(cmdline), "netsh interface ipv4 set subinterface \"%s\" mtu=%d", this->device, mtu); cmdline << "netsh interface ipv4 set subinterface \"" << this->device
winsystem(cmdline); << "\" mtu=" << mtu;
winsystem(cmdline.str().data());
#else #else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s mtu %u", this->device, mtu); cmdline << "/sbin/ifconfig " << this->device << " mtu " << mtu;
if (system(cmdline) != 0) if (system(cmdline.str().data()) != 0)
syslog(LOG_ERR, "could not set tun device mtu"); syslog(LOG_ERR, "could not set tun device mtu");
#endif #endif
} }
Tun::~Tun() Tun::~Tun()
{ {
tun_close(fd, device); tun_close(fd, &device[0]);
} }
void Tun::setIp(uint32_t ip, uint32_t destIp) void Tun::setIp(uint32_t ip, uint32_t destIp)
{ {
char cmdline[512]; std::stringstream cmdline;
string ips = Utility::formatIp(ip); string ips = Utility::formatIp(ip);
string destIps = Utility::formatIp(destIp); string destIps = Utility::formatIp(destIp);
#ifdef WIN32 #ifdef WIN32
snprintf(cmdline, sizeof(cmdline), "netsh interface ip set address name=\"%s\" " cmdline << "netsh interface ip set address name=\"" << device << "\" "
"static %s 255.255.255.0", device, ips.c_str()); << "static " << ips << " 255.255.255.0";
winsystem(cmdline); winsystem(cmdline.str().data());
if (!tun_set_ip(fd, ip, ip & 0xffffff00, 0xffffff00)) if (!tun_set_ip(fd, ip, ip & 0xffffff00, 0xffffff00))
syslog(LOG_ERR, "could not set tun device driver ip address: %s", tun_last_error()); syslog(LOG_ERR, "could not set tun device driver ip address: %s", tun_last_error());
#elif LINUX #elif LINUX
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s netmask 255.255.255.0", device, ips.c_str()); cmdline << "/sbin/ifconfig " << device << " " << ips << " netmask 255.255.255.0";
if (system(cmdline) != 0) if (system(cmdline.str().data()) != 0)
syslog(LOG_ERR, "could not set tun device ip address"); syslog(LOG_ERR, "could not set tun device ip address");
#else #else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str()); cmdline << "/sbin/ifconfig " << device << " " << ips << " " << destIps
if (system(cmdline) != 0) << " netmask 255.255.255.255";
if (system(cmdline.str().data()) != 0)
syslog(LOG_ERR, "could not set tun device ip address"); syslog(LOG_ERR, "could not set tun device ip address");
#endif #endif
} }

View File

@ -28,7 +28,7 @@
class Tun class Tun
{ {
public: public:
Tun(const char *device, int mtu); Tun(const std::string *device, int mtu);
~Tun(); ~Tun();
int getFd() { return fd; } int getFd() { return fd; }
@ -40,7 +40,7 @@ public:
void setIp(uint32_t ip, uint32_t destIp); void setIp(uint32_t ip, uint32_t destIp);
protected: protected:
char device[VTUN_DEV_LEN]; std::string device;
int mtu; int mtu;
int fd; int fd;

View File

@ -22,14 +22,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <sstream>
using namespace std; std::string Utility::formatIp(uint32_t ip)
string Utility::formatIp(uint32_t ip)
{ {
char buffer[16]; std::stringstream s;
sprintf(buffer, "%d.%d.%d.%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); s << ((ip >> 24) & 0xff) << '.'
return buffer; << ((ip >> 16) & 0xff) << '.'
<< ((ip >> 8) & 0xff) << '.'
<< ((ip >> 0) & 0xff);
return s.str();
} }
int Utility::rand() int Utility::rand()

View File

@ -28,9 +28,10 @@
#include <unistd.h> #include <unistd.h>
#include <sys/select.h> #include <sys/select.h>
#include <grp.h> #include <grp.h>
#include <stdio.h> #include <iostream>
using namespace std; using std::cout;
using std::endl;
Worker::TunnelHeader::Magic::Magic(const char *magic) Worker::TunnelHeader::Magic::Magic(const char *magic)
{ {
@ -48,54 +49,37 @@ bool Worker::TunnelHeader::Magic::operator!=(const Magic &other) const
return memcmp(data, other.data, sizeof(data)) != 0; return memcmp(data, other.data, sizeof(data)) != 0;
} }
Worker::Worker(int tunnelMtu, const char *deviceName, bool answerEcho, uid_t uid, gid_t gid) Worker::Worker(int tunnelMtu, const std::string *deviceName, bool answerEcho,
uid_t uid, gid_t gid)
: echo(tunnelMtu + sizeof(TunnelHeader)), tun(deviceName, tunnelMtu)
{ {
this->tunnelMtu = tunnelMtu; this->tunnelMtu = tunnelMtu;
this->answerEcho = answerEcho; this->answerEcho = answerEcho;
this->uid = uid; this->uid = uid;
this->gid = gid; this->gid = gid;
this->privilegesDropped = false; this->privilegesDropped = false;
echo = NULL;
tun = NULL;
try
{
echo = new Echo(tunnelMtu + sizeof(TunnelHeader));
tun = new Tun(deviceName, tunnelMtu);
}
catch (...)
{
delete echo;
delete tun;
throw;
}
} }
Worker::~Worker() void Worker::sendEcho(const TunnelHeader::Magic &magic, TunnelHeader::Type type,
{ int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
delete echo;
delete tun;
}
void Worker::sendEcho(const TunnelHeader::Magic &magic, int type, int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
{ {
if (length > payloadBufferSize()) if (length > payloadBufferSize())
throw Exception("packet too big"); throw Exception("packet too big");
TunnelHeader *header = (TunnelHeader *)echo->sendPayloadBuffer(); TunnelHeader *header = (TunnelHeader *)echo.sendPayloadBuffer();
header->magic = magic; header->magic = magic;
header->type = type; header->type = type;
DEBUG_ONLY(printf("sending: type %d, length %d, id %d, seq %d\n", type, length, id, seq)); DEBUG_ONLY(
cout << "sending: type " << type << ", length " << length
<< ", id " << id << ", seq " << seq << endl);
echo->send(length + sizeof(TunnelHeader), realIp, reply, id, seq); echo.send(length + sizeof(TunnelHeader), realIp, reply, id, seq);
} }
void Worker::sendToTun(int length) void Worker::sendToTun(int length)
{ {
tun->write(echoReceivePayloadBuffer(), length); tun.write(echoReceivePayloadBuffer(), length);
} }
void Worker::setTimeout(Time delta) void Worker::setTimeout(Time delta)
@ -108,7 +92,7 @@ void Worker::run()
now = Time::now(); now = Time::now();
alive = true; alive = true;
int maxFd = echo->getFd() > tun->getFd() ? echo->getFd() : tun->getFd(); int maxFd = echo.getFd() > tun.getFd() ? echo.getFd() : tun.getFd();
while (alive) while (alive)
{ {
@ -116,8 +100,8 @@ void Worker::run()
Time timeout; Time timeout;
FD_ZERO(&fs); FD_ZERO(&fs);
FD_SET(tun->getFd(), &fs); FD_SET(tun.getFd(), &fs);
FD_SET(echo->getFd(), &fs); FD_SET(echo.getFd(), &fs);
if (nextTimeout != Time::ZERO) if (nextTimeout != Time::ZERO)
{ {
@ -127,7 +111,8 @@ void Worker::run()
} }
// wait for data or timeout // wait for data or timeout
int result = select(maxFd + 1 , &fs, NULL, NULL, nextTimeout != Time::ZERO ? &timeout.getTimeval() : NULL); timeval *timeval = nextTimeout != Time::ZERO ? &timeout.getTimeval() : NULL;
int result = select(maxFd + 1 , &fs, NULL, NULL, timeval);
if (result == -1) if (result == -1)
{ {
if (alive) if (alive)
@ -146,43 +131,43 @@ void Worker::run()
} }
// icmp data // icmp data
if (FD_ISSET(echo->getFd(), &fs)) if (FD_ISSET(echo.getFd(), &fs))
{ {
bool reply; bool reply;
uint16_t id, seq; uint16_t id, seq;
uint32_t ip; uint32_t ip;
int dataLength = echo->receive(ip, reply, id, seq); int dataLength = echo.receive(ip, reply, id, seq);
if (dataLength != -1) if (dataLength != -1)
{ {
bool valid = dataLength >= sizeof(TunnelHeader); bool valid = dataLength >= sizeof(TunnelHeader);
if (valid) if (valid)
{ {
TunnelHeader *header = (TunnelHeader *)echo->receivePayloadBuffer(); TunnelHeader *header = (TunnelHeader *)echo.receivePayloadBuffer();
DEBUG_ONLY( DEBUG_ONLY(
printf("received: type %d, length %d, id %d, seq %d\n", cout << "received: type " << header->type
header->type, (int)(dataLength - sizeof(TunnelHeader)), << ", length " << dataLength - sizeof(TunnelHeader)
id, seq)); << ", id " << id << ", seq " << seq << endl);
valid = handleEchoData(*header, dataLength - sizeof(TunnelHeader), ip, reply, id, seq); valid = handleEchoData(*header, dataLength - sizeof(TunnelHeader), ip, reply, id, seq);
} }
if (!valid && !reply && answerEcho) if (!valid && !reply && answerEcho)
{ {
memcpy(echo->sendPayloadBuffer(), echo->receivePayloadBuffer(), dataLength); memcpy(echo.sendPayloadBuffer(), echo.receivePayloadBuffer(), dataLength);
echo->send(dataLength, ip, true, id, seq); echo.send(dataLength, ip, true, id, seq);
} }
} }
} }
// data from tun // data from tun
if (FD_ISSET(tun->getFd(), &fs)) if (FD_ISSET(tun.getFd(), &fs))
{ {
uint32_t sourceIp, destIp; uint32_t sourceIp, destIp;
int dataLength = tun->read(echoSendPayloadBuffer(), sourceIp, destIp); int dataLength = tun.read(echoSendPayloadBuffer(), sourceIp, destIp);
if (dataLength == 0) if (dataLength == 0)
throw Exception("tunnel closed"); throw Exception("tunnel closed");
@ -232,10 +217,10 @@ void Worker::handleTimeout() { }
char *Worker::echoSendPayloadBuffer() char *Worker::echoSendPayloadBuffer()
{ {
return echo->sendPayloadBuffer() + sizeof(TunnelHeader); return echo.sendPayloadBuffer() + sizeof(TunnelHeader);
} }
char *Worker::echoReceivePayloadBuffer() char *Worker::echoReceivePayloadBuffer()
{ {
return echo->receivePayloadBuffer() + sizeof(TunnelHeader); return echo.receivePayloadBuffer() + sizeof(TunnelHeader);
} }

View File

@ -30,8 +30,9 @@
class Worker class Worker
{ {
public: public:
Worker(int tunnelMtu, const char *deviceName, bool answerEcho, uid_t uid, gid_t gid); Worker(int tunnelMtu, const std::string *deviceName, bool answerEcho,
virtual ~Worker(); uid_t uid, gid_t gid);
virtual ~Worker() { }
virtual void run(); virtual void run();
virtual void stop(); virtual void stop();
@ -52,21 +53,21 @@ protected:
char data[4]; char data[4];
}; };
Magic magic;
uint8_t type;
enum Type enum Type
{ {
TYPE_RESET_CONNECTION = 1, TYPE_RESET_CONNECTION = 1,
TYPE_CONNECTION_REQUEST = 2, TYPE_CONNECTION_REQUEST = 2,
TYPE_CHALLENGE = 3, TYPE_CHALLENGE = 3,
TYPE_CHALLENGE_RESPONSE = 4, TYPE_CHALLENGE_RESPONSE = 4,
TYPE_CONNECTION_ACCEPT = 5, TYPE_CONNECTION_ACCEPT = 5,
TYPE_CHALLENGE_ERROR = 6, TYPE_CHALLENGE_ERROR = 6,
TYPE_DATA = 7, TYPE_DATA = 7,
TYPE_POLL = 8, TYPE_POLL = 8,
TYPE_SERVER_FULL = 9 TYPE_SERVER_FULL = 9
}; };
Magic magic;
uint8_t type;
}; // size = 5 }; // size = 5
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, virtual bool handleEchoData(const TunnelHeader &header, int dataLength,
@ -75,8 +76,8 @@ protected:
uint32_t destIp); // to echoSendPayloadBuffer uint32_t destIp); // to echoSendPayloadBuffer
virtual void handleTimeout(); virtual void handleTimeout();
void sendEcho(const TunnelHeader::Magic &magic, int type, int length, void sendEcho(const TunnelHeader::Magic &magic, TunnelHeader::Type type,
uint32_t realIp, bool reply, uint16_t id, uint16_t seq); int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
void sendToTun(int length); // from echoReceivePayloadBuffer void sendToTun(int length); // from echoReceivePayloadBuffer
void setTimeout(Time delta); void setTimeout(Time delta);
@ -88,8 +89,8 @@ protected:
void dropPrivileges(); void dropPrivileges();
Echo *echo; Echo echo;
Tun *tun; Tun tun;
bool alive; bool alive;
bool answerEcho; bool answerEcho;
int tunnelMtu; int tunnelMtu;