Changed tabs to spaces

This commit is contained in:
Friedrich Schöller 2012-09-20 13:43:47 +02:00
parent 832e2ee3ae
commit 8014a9641f
26 changed files with 989 additions and 989 deletions

View File

@ -7,47 +7,47 @@ GPP = g++
all: hans
hans: tun.o sha1.o main.o client.o server.o auth.o worker.o time.o tun_dev.o echo.o exception.o utility.o
$(GPP) -o hans tun.o sha1.o main.o client.o server.o auth.o worker.o time.o tun_dev.o echo.o exception.o utility.o $(LDFLAGS)
$(GPP) -o hans tun.o sha1.o main.o client.o server.o auth.o worker.o time.o tun_dev.o echo.o exception.o utility.o $(LDFLAGS)
utility.o: utility.cpp utility.h
$(GPP) -c utility.cpp $(CFLAGS)
$(GPP) -c utility.cpp $(CFLAGS)
exception.o: exception.cpp exception.h
$(GPP) -c exception.cpp $(CFLAGS)
$(GPP) -c exception.cpp $(CFLAGS)
echo.o: echo.cpp echo.h exception.h
$(GPP) -c echo.cpp $(CFLAGS)
$(GPP) -c echo.cpp $(CFLAGS)
tun.o: tun.cpp tun.h exception.h utility.h tun_dev.h
$(GPP) -c tun.cpp $(CFLAGS)
$(GPP) -c tun.cpp $(CFLAGS)
tun_dev.o:
$(GCC) -c $(TUN_DEV_FILE) -o tun_dev.o $(CFLAGS)
$(GCC) -c $(TUN_DEV_FILE) -o tun_dev.o $(CFLAGS)
sha1.o: sha1.cpp sha1.h
$(GPP) -c sha1.cpp $(CFLAGS)
$(GPP) -c sha1.cpp $(CFLAGS)
main.o: main.cpp client.h server.h exception.h worker.h auth.h time.h echo.h tun.h tun_dev.h
$(GPP) -c main.cpp $(CFLAGS)
$(GPP) -c main.cpp $(CFLAGS)
client.o: client.cpp client.h server.h exception.h config.h worker.h auth.h time.h echo.h tun.h tun_dev.h
$(GPP) -c client.cpp $(CFLAGS)
$(GPP) -c client.cpp $(CFLAGS)
server.o: server.cpp server.h client.h utility.h config.h worker.h auth.h time.h echo.h tun.h tun_dev.h
$(GPP) -c server.cpp $(CFLAGS)
$(GPP) -c server.cpp $(CFLAGS)
auth.o: auth.cpp auth.h sha1.h utility.h
$(GPP) -c auth.cpp $(CFLAGS)
$(GPP) -c auth.cpp $(CFLAGS)
worker.o: worker.cpp worker.h tun.h exception.h time.h echo.h tun_dev.h config.h
$(GPP) -c worker.cpp $(CFLAGS)
$(GPP) -c worker.cpp $(CFLAGS)
time.o: time.cpp time.h
$(GPP) -c time.cpp $(CFLAGS)
$(GPP) -c time.cpp $(CFLAGS)
clean:
rm -f tun.o sha1.o main.o client.o server.o auth.o worker.o time.o tun_dev.o echo.o exception.o utility.o tunemu.o hans
rm -f tun.o sha1.o main.o client.o server.o auth.o worker.o time.o tun_dev.o echo.o exception.o utility.o tunemu.o hans
tunemu.o: tunemu.h tunemu.c
$(GCC) -c tunemu.c -o tunemu.o
$(GCC) -c tunemu.c -o tunemu.o

View File

@ -25,33 +25,33 @@
Auth::Auth(const char *passphrase)
{
this->passphrase = passphrase;
this->passphrase = passphrase;
}
Auth::Response Auth::getResponse(const Challenge &challenge) const
{
SHA1 hasher;
SHA1 hasher;
Response response;
Response response;
hasher << passphrase.c_str();
hasher.Input(&challenge[0], challenge.size());
hasher << passphrase.c_str();
hasher.Input(&challenge[0], challenge.size());
hasher.Result((unsigned int *)response.data);
for (int i = 0; i < 5; i++)
response.data[i] = htonl(response.data[i]);
hasher.Result((unsigned int *)response.data);
for (int i = 0; i < 5; i++)
response.data[i] = htonl(response.data[i]);
return response;
return response;
}
Auth::Challenge Auth::generateChallenge(int length) const
{
Challenge challenge;
challenge.resize(length);
Challenge challenge;
challenge.resize(length);
for (int i = 0; i < length; i++)
challenge[i] = Utility::rand();
for (int i = 0; i < length; i++)
challenge[i] = Utility::rand();
return challenge;
return challenge;
}

22
auth.h
View File

@ -28,22 +28,22 @@
class Auth
{
public:
typedef std::vector<char> Challenge;
typedef std::vector<char> Challenge;
struct Response
{
uint32_t data[5];
bool operator==(const Response &other) const { return memcmp(this, &other, sizeof(Response)) == 0; }
};
struct Response
{
uint32_t data[5];
bool operator==(const Response &other) const { return memcmp(this, &other, sizeof(Response)) == 0; }
};
Auth(const char *passphrase);
Auth(const char *passphrase);
Challenge generateChallenge(int length) const;
Response getResponse(const Challenge &challenge) const;
Challenge generateChallenge(int length) const;
Response getResponse(const Challenge &challenge) const;
protected:
std::string passphrase;
std::string challenge;
std::string passphrase;
std::string challenge;
};
#endif

View File

@ -36,16 +36,16 @@ Client::Client(int tunnelMtu, const char *deviceName, uint32_t serverIp,
bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp)
: Worker(tunnelMtu, deviceName, false, uid, gid), auth(passphrase)
{
this->serverIp = serverIp;
this->serverIp = serverIp;
this->clientIp = INADDR_NONE;
this->desiredIp = desiredIp;
this->maxPolls = maxPolls;
this->nextEchoId = Utility::rand();
this->changeEchoId = changeEchoId;
this->changeEchoSeq = changeEchoSeq;
this->nextEchoSequence = Utility::rand();
this->maxPolls = maxPolls;
this->nextEchoId = Utility::rand();
this->changeEchoId = changeEchoId;
this->changeEchoSeq = changeEchoSeq;
this->nextEchoSequence = Utility::rand();
state = STATE_CLOSED;
state = STATE_CLOSED;
}
Client::~Client()
@ -55,82 +55,82 @@ Client::~Client()
void Client::sendConnectionRequest()
{
Server::ClientConnectData *connectData = (Server::ClientConnectData *)echoSendPayloadBuffer();
connectData->maxPolls = maxPolls;
Server::ClientConnectData *connectData = (Server::ClientConnectData *)echoSendPayloadBuffer();
connectData->maxPolls = maxPolls;
connectData->desiredIp = desiredIp;
syslog(LOG_DEBUG, "sending connection request");
syslog(LOG_DEBUG, "sending connection request");
sendEchoToServer(TunnelHeader::TYPE_CONNECTION_REQUEST, sizeof(Server::ClientConnectData));
sendEchoToServer(TunnelHeader::TYPE_CONNECTION_REQUEST, sizeof(Server::ClientConnectData));
state = STATE_CONNECTION_REQUEST_SENT;
setTimeout(5000);
state = STATE_CONNECTION_REQUEST_SENT;
setTimeout(5000);
}
void Client::sendChallengeResponse(int dataLength)
{
if (dataLength != CHALLENGE_SIZE)
throw Exception("invalid challenge received");
if (dataLength != CHALLENGE_SIZE)
throw Exception("invalid challenge received");
state = STATE_CHALLENGE_RESPONSE_SENT;
state = STATE_CHALLENGE_RESPONSE_SENT;
syslog(LOG_DEBUG, "sending challenge response");
syslog(LOG_DEBUG, "sending challenge response");
vector<char> challenge;
challenge.resize(dataLength);
memcpy(&challenge[0], echoReceivePayloadBuffer(), dataLength);
vector<char> challenge;
challenge.resize(dataLength);
memcpy(&challenge[0], echoReceivePayloadBuffer(), dataLength);
Auth::Response response = auth.getResponse(challenge);
Auth::Response response = auth.getResponse(challenge);
memcpy(echoSendPayloadBuffer(), (char *)&response, sizeof(Auth::Response));
sendEchoToServer(TunnelHeader::TYPE_CHALLENGE_RESPONSE, sizeof(Auth::Response));
memcpy(echoSendPayloadBuffer(), (char *)&response, sizeof(Auth::Response));
sendEchoToServer(TunnelHeader::TYPE_CHALLENGE_RESPONSE, sizeof(Auth::Response));
setTimeout(5000);
setTimeout(5000);
}
bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
{
if (realIp != serverIp || !reply)
return false;
if (realIp != serverIp || !reply)
return false;
if (header.magic != Server::magic)
return false;
if (header.magic != Server::magic)
return false;
switch (header.type)
{
case TunnelHeader::TYPE_RESET_CONNECTION:
syslog(LOG_DEBUG, "reset reveiced");
switch (header.type)
{
case TunnelHeader::TYPE_RESET_CONNECTION:
syslog(LOG_DEBUG, "reset reveiced");
sendConnectionRequest();
return true;
case TunnelHeader::TYPE_SERVER_FULL:
if (state == STATE_CONNECTION_REQUEST_SENT)
{
throw Exception("server full");
}
break;
case TunnelHeader::TYPE_CHALLENGE:
if (state == STATE_CONNECTION_REQUEST_SENT)
{
syslog(LOG_DEBUG, "challenge received");
sendChallengeResponse(dataLength);
return true;
}
break;
case TunnelHeader::TYPE_CONNECTION_ACCEPT:
if (state == STATE_CHALLENGE_RESPONSE_SENT)
{
if (dataLength != sizeof(uint32_t))
{
throw Exception("invalid ip received");
return true;
}
sendConnectionRequest();
return true;
case TunnelHeader::TYPE_SERVER_FULL:
if (state == STATE_CONNECTION_REQUEST_SENT)
{
throw Exception("server full");
}
break;
case TunnelHeader::TYPE_CHALLENGE:
if (state == STATE_CONNECTION_REQUEST_SENT)
{
syslog(LOG_DEBUG, "challenge received");
sendChallengeResponse(dataLength);
return true;
}
break;
case TunnelHeader::TYPE_CONNECTION_ACCEPT:
if (state == STATE_CHALLENGE_RESPONSE_SENT)
{
if (dataLength != sizeof(uint32_t))
{
throw Exception("invalid ip received");
return true;
}
syslog(LOG_INFO, "connection established");
syslog(LOG_INFO, "connection established");
uint32_t ip = ntohl(*(uint32_t *)echoReceivePayloadBuffer());
uint32_t ip = ntohl(*(uint32_t *)echoReceivePayloadBuffer());
if (ip != clientIp)
{
{
if (privilegesDropped)
throw Exception("could not get the same ip address, so root privileges are required to change it");
@ -138,106 +138,106 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
desiredIp = ip;
tun->setIp(ip, (ip & 0xffffff00) + 1, false);
}
state = STATE_ESTABLISHED;
state = STATE_ESTABLISHED;
dropPrivileges();
startPolling();
dropPrivileges();
startPolling();
return true;
}
break;
case TunnelHeader::TYPE_CHALLENGE_ERROR:
if (state == STATE_CHALLENGE_RESPONSE_SENT)
{
throw Exception("password error");
}
break;
case TunnelHeader::TYPE_DATA:
if (state == STATE_ESTABLISHED)
{
handleDataFromServer(dataLength);
return true;
}
break;
}
return true;
}
break;
case TunnelHeader::TYPE_CHALLENGE_ERROR:
if (state == STATE_CHALLENGE_RESPONSE_SENT)
{
throw Exception("password error");
}
break;
case TunnelHeader::TYPE_DATA:
if (state == STATE_ESTABLISHED)
{
handleDataFromServer(dataLength);
return true;
}
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);
return true;
return true;
}
void Client::sendEchoToServer(int type, int dataLength)
{
if (maxPolls == 0 && state == STATE_ESTABLISHED)
setTimeout(KEEP_ALIVE_INTERVAL);
if (maxPolls == 0 && state == STATE_ESTABLISHED)
setTimeout(KEEP_ALIVE_INTERVAL);
sendEcho(magic, type, dataLength, serverIp, false, nextEchoId, nextEchoSequence);
sendEcho(magic, type, dataLength, serverIp, false, nextEchoId, nextEchoSequence);
if (changeEchoId)
nextEchoId = nextEchoId + 38543; // some random prime
if (changeEchoSeq)
nextEchoSequence = nextEchoSequence + 38543; // some random prime
if (changeEchoId)
nextEchoId = nextEchoId + 38543; // some random prime
if (changeEchoSeq)
nextEchoSequence = nextEchoSequence + 38543; // some random prime
}
void Client::startPolling()
{
if (maxPolls == 0)
{
setTimeout(KEEP_ALIVE_INTERVAL);
}
else
{
for (int i = 0; i < maxPolls; i++)
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
setTimeout(POLL_INTERVAL);
}
if (maxPolls == 0)
{
setTimeout(KEEP_ALIVE_INTERVAL);
}
else
{
for (int i = 0; i < maxPolls; i++)
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
setTimeout(POLL_INTERVAL);
}
}
void Client::handleDataFromServer(int dataLength)
{
if (dataLength == 0)
{
syslog(LOG_WARNING, "received empty data packet");
return;
}
if (dataLength == 0)
{
syslog(LOG_WARNING, "received empty data packet");
return;
}
sendToTun(dataLength);
sendToTun(dataLength);
if (maxPolls != 0)
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
if (maxPolls != 0)
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
}
void Client::handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp)
{
if (state != STATE_ESTABLISHED)
return;
if (state != STATE_ESTABLISHED)
return;
sendEchoToServer(TunnelHeader::TYPE_DATA, dataLength);
sendEchoToServer(TunnelHeader::TYPE_DATA, dataLength);
}
void Client::handleTimeout()
{
switch (state)
{
case STATE_CONNECTION_REQUEST_SENT:
case STATE_CHALLENGE_RESPONSE_SENT:
sendConnectionRequest();
break;
switch (state)
{
case STATE_CONNECTION_REQUEST_SENT:
case STATE_CHALLENGE_RESPONSE_SENT:
sendConnectionRequest();
break;
case STATE_ESTABLISHED:
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
setTimeout(maxPolls == 0 ? KEEP_ALIVE_INTERVAL : POLL_INTERVAL);
break;
case STATE_CLOSED:
break;
}
case STATE_ESTABLISHED:
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
setTimeout(maxPolls == 0 ? KEEP_ALIVE_INTERVAL : POLL_INTERVAL);
break;
case STATE_CLOSED:
break;
}
}
void Client::run()
{
now = Time::now();
now = Time::now();
sendConnectionRequest();
sendConnectionRequest();
Worker::run();
Worker::run();
}

View File

@ -28,50 +28,50 @@
class Client : public Worker
{
public:
Client(int tunnelMtu, const char *deviceName, uint32_t serverIp,
Client(int tunnelMtu, const char *deviceName, uint32_t serverIp,
int maxPolls, const char *passphrase, uid_t uid, gid_t gid,
bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp);
virtual ~Client();
virtual ~Client();
virtual void run();
virtual void run();
static const Worker::TunnelHeader::Magic magic;
static const Worker::TunnelHeader::Magic magic;
protected:
enum State
{
STATE_CLOSED,
STATE_CONNECTION_REQUEST_SENT,
STATE_CHALLENGE_RESPONSE_SENT,
STATE_ESTABLISHED
};
enum State
{
STATE_CLOSED,
STATE_CONNECTION_REQUEST_SENT,
STATE_CHALLENGE_RESPONSE_SENT,
STATE_ESTABLISHED
};
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
virtual void handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp);
virtual void handleTimeout();
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
virtual void handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp);
virtual void handleTimeout();
void handleDataFromServer(int length);
void handleDataFromServer(int length);
void startPolling();
void startPolling();
void sendEchoToServer(int type, int dataLength);
void sendChallengeResponse(int dataLength);
void sendConnectionRequest();
void sendEchoToServer(int type, int dataLength);
void sendChallengeResponse(int dataLength);
void sendConnectionRequest();
Auth auth;
Auth auth;
uint32_t serverIp;
uint32_t serverIp;
uint32_t clientIp;
uint32_t desiredIp;
int maxPolls;
int pollTimeoutNr;
int maxPolls;
int pollTimeoutNr;
bool changeEchoId, changeEchoSeq;
bool changeEchoId, changeEchoSeq;
uint16_t nextEchoId;
uint16_t nextEchoSequence;
uint16_t nextEchoId;
uint16_t nextEchoSequence;
State state;
State state;
};
#endif

View File

@ -34,88 +34,88 @@ typedef ip IpHeader;
Echo::Echo(int maxPayloadSize)
{
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (fd == -1)
throw Exception("creating icmp socket", true);
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (fd == -1)
throw Exception("creating icmp socket", true);
bufferSize = maxPayloadSize + headerSize();
sendBuffer = new char[bufferSize];
receiveBuffer = new char[bufferSize];
bufferSize = maxPayloadSize + headerSize();
sendBuffer = new char[bufferSize];
receiveBuffer = new char[bufferSize];
}
Echo::~Echo()
{
close(fd);
close(fd);
delete[] sendBuffer;
delete[] receiveBuffer;
delete[] sendBuffer;
delete[] receiveBuffer;
}
int Echo::headerSize()
{
return sizeof(IpHeader) + sizeof(EchoHeader);
return sizeof(IpHeader) + sizeof(EchoHeader);
}
void Echo::send(int payloadLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
{
struct sockaddr_in target;
target.sin_family = AF_INET;
target.sin_addr.s_addr = htonl(realIp);
struct sockaddr_in target;
target.sin_family = AF_INET;
target.sin_addr.s_addr = htonl(realIp);
if (payloadLength + sizeof(IpHeader) + sizeof(EchoHeader) > bufferSize)
throw Exception("packet too big");
if (payloadLength + sizeof(IpHeader) + sizeof(EchoHeader) > bufferSize)
throw Exception("packet too big");
EchoHeader *header = (EchoHeader *)(sendBuffer + sizeof(IpHeader));
header->type = reply ? 0: 8;
header->code = 0;
header->id = htons(id);
header->seq = htons(seq);
header->chksum = 0;
header->chksum = icmpChecksum(sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader));
EchoHeader *header = (EchoHeader *)(sendBuffer + sizeof(IpHeader));
header->type = reply ? 0: 8;
header->code = 0;
header->id = htons(id);
header->seq = htons(seq);
header->chksum = 0;
header->chksum = icmpChecksum(sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader));
int result = sendto(fd, sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
if (result == -1)
int result = sendto(fd, sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
if (result == -1)
syslog(LOG_ERR, "error sending icmp packet: %s", strerror(errno));
}
int Echo::receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq)
{
struct sockaddr_in source;
int source_addr_len = sizeof(struct sockaddr_in);
struct sockaddr_in source;
int source_addr_len = sizeof(struct sockaddr_in);
int dataLength = recvfrom(fd, receiveBuffer, bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
if (dataLength == -1)
int dataLength = recvfrom(fd, receiveBuffer, bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
if (dataLength == -1)
{
syslog(LOG_ERR, "error receiving icmp packet: %s", strerror(errno));
return -1;
}
if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader))
return -1;
if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader))
return -1;
EchoHeader *header = (EchoHeader *)(receiveBuffer + sizeof(IpHeader));
if ((header->type != 0 && header->type != 8) || header->code != 0)
return -1;
EchoHeader *header = (EchoHeader *)(receiveBuffer + sizeof(IpHeader));
if ((header->type != 0 && header->type != 8) || header->code != 0)
return -1;
realIp = ntohl(source.sin_addr.s_addr);
reply = header->type == 0;
id = ntohs(header->id);
seq = ntohs(header->seq);
realIp = ntohl(source.sin_addr.s_addr);
reply = header->type == 0;
id = ntohs(header->id);
seq = ntohs(header->seq);
return dataLength - sizeof(IpHeader) - sizeof(EchoHeader);
return dataLength - sizeof(IpHeader) - sizeof(EchoHeader);
}
uint16_t Echo::icmpChecksum(const char *data, int length)
{
uint16_t *data16 = (uint16_t *)data;
uint32_t sum = 0;
for (sum = 0; length > 1; length -= 2)
sum += *data16++;
if (length == 1)
sum += *(unsigned char *)data16;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
uint16_t *data16 = (uint16_t *)data;
uint32_t sum = 0;
for (sum = 0; length > 1; length -= 2)
sum += *data16++;
if (length == 1)
sum += *(unsigned char *)data16;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}

40
echo.h
View File

@ -26,33 +26,33 @@
class Echo
{
public:
Echo(int maxPayloadSize);
~Echo();
Echo(int maxPayloadSize);
~Echo();
int getFd() { return fd; }
int getFd() { return fd; }
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);
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);
char *sendPayloadBuffer() { return sendBuffer + headerSize(); }
char *receivePayloadBuffer() { return receiveBuffer + headerSize(); }
char *sendPayloadBuffer() { return sendBuffer + headerSize(); }
char *receivePayloadBuffer() { return receiveBuffer + headerSize(); }
static int headerSize();
static int headerSize();
protected:
struct EchoHeader
{
uint8_t type;
uint8_t code;
uint16_t chksum;
uint16_t id;
uint16_t seq;
}; // size = 8
struct EchoHeader
{
uint8_t type;
uint8_t code;
uint16_t chksum;
uint16_t id;
uint16_t seq;
}; // size = 8
uint16_t icmpChecksum(const char *data, int length);
uint16_t icmpChecksum(const char *data, int length);
int fd;
int bufferSize;
char *sendBuffer, *receiveBuffer;
int fd;
int bufferSize;
char *sendBuffer, *receiveBuffer;
};
#endif

View File

@ -26,13 +26,13 @@ using namespace std;
Exception::Exception(const char *msg)
{
this->msg = msg;
this->msg = msg;
}
Exception::Exception(const char *msg, bool appendSystemError)
{
if (appendSystemError)
this->msg = string(msg) + ": " + strerror(errno);
else
this->msg = msg;
if (appendSystemError)
this->msg = string(msg) + ": " + strerror(errno);
else
this->msg = msg;
}

View File

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

316
main.cpp
View File

@ -33,184 +33,184 @@
void usage()
{
printf(
"Hans - IP over ICMP version 0.4.1\n\n"
"RUN AS SERVER\n"
" hans -s network [-fvr] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu] [-a ip]\n\n"
"RUN AS CLIENT\n"
" hans -c server [-fv] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu] [-w polls]\n\n"
"ARGUMENTS\n"
" -s network Run as a server with the given network address for the virtual interface.\n"
" -c server Connect to a server.\n"
" -f Run in foreground.\n"
" -v Print debug information.\n"
" -r Respond to ordinary pings. Only in server mode.\n"
" -p password Use a password.\n"
" -u username Set the user under which the program should run.\n"
" -d device Use the given tun device.\n"
" -m mtu Use this mtu to calculate the tunnel mtu.\n"
" The generated echo packets will not be bigger than this value.\n"
" Has to be the same on client and server. Defaults to 1500.\n"
" -w polls Number of echo requests the client sends to the server for polling.\n"
" 0 disables polling. Defaults to 10.\n"
" -i Change the echo id for every echo request.\n"
printf(
"Hans - IP over ICMP version 0.4.1\n\n"
"RUN AS SERVER\n"
" hans -s network [-fvr] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu] [-a ip]\n\n"
"RUN AS CLIENT\n"
" hans -c server [-fv] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu] [-w polls]\n\n"
"ARGUMENTS\n"
" -s network Run as a server with the given network address for the virtual interface.\n"
" -c server Connect to a server.\n"
" -f Run in foreground.\n"
" -v Print debug information.\n"
" -r Respond to ordinary pings. Only in server mode.\n"
" -p password Use a password.\n"
" -u username Set the user under which the program should run.\n"
" -d device Use the given tun device.\n"
" -m mtu Use this mtu to calculate the tunnel mtu.\n"
" The generated echo packets will not be bigger than this value.\n"
" Has to be the same on client and server. Defaults to 1500.\n"
" -w polls Number of echo requests the client sends to the server for polling.\n"
" 0 disables polling. Defaults to 10.\n"
" -i Change the echo id for every echo request.\n"
" -q Change the echo sequence number for every echo request.\n"
" -a ip Try to get assigned the given tunnel ip address.\n"
);
);
}
int main(int argc, char *argv[])
{
const char *serverName;
const char *userName = NULL;
const char *password = "";
const char *device = NULL;
bool isServer = false;
bool isClient = false;
bool foreground = false;
int mtu = 1500;
int maxPolls = 10;
uint32_t network = INADDR_NONE;
const char *serverName;
const char *userName = NULL;
const char *password = "";
const char *device = NULL;
bool isServer = false;
bool isClient = false;
bool foreground = false;
int mtu = 1500;
int maxPolls = 10;
uint32_t network = INADDR_NONE;
uint32_t clientIp = INADDR_NONE;
bool answerPing = false;
uid_t uid = 0;
gid_t gid = 0;
bool changeEchoId = false;
bool changeEchoSeq = false;
bool verbose = false;
openlog(argv[0], LOG_PERROR, LOG_DAEMON);
bool answerPing = false;
uid_t uid = 0;
gid_t gid = 0;
bool changeEchoId = false;
bool changeEchoSeq = false;
bool verbose = false;
openlog(argv[0], LOG_PERROR, LOG_DAEMON);
int c;
while ((c = getopt(argc, argv, "fru:d:p:s:c:m:w:qiva:")) != -1)
{
switch(c) {
case 'f':
foreground = true;
break;
case 'u':
userName = optarg;
break;
case 'd':
device = optarg;
break;
case 'p':
password = strdup(optarg);
memset(optarg, 0, strlen(optarg));
break;
case 'c':
isClient = true;
serverName = optarg;
break;
case 's':
isServer = true;
network = ntohl(inet_addr(optarg));
if (network == INADDR_NONE)
printf("invalid network\n");
break;
case 'm':
mtu = atoi(optarg);
break;
case 'w':
maxPolls = atoi(optarg);
break;
case 'r':
answerPing = true;
break;
case 'q':
changeEchoSeq = true;
break;
case 'i':
changeEchoId = true;
break;
case 'v':
verbose = true;
break;
case 'a':
clientIp = ntohl(inet_addr(optarg));
break;
default:
usage();
return 1;
}
}
int c;
while ((c = getopt(argc, argv, "fru:d:p:s:c:m:w:qiva:")) != -1)
{
switch(c) {
case 'f':
foreground = true;
break;
case 'u':
userName = optarg;
break;
case 'd':
device = optarg;
break;
case 'p':
password = strdup(optarg);
memset(optarg, 0, strlen(optarg));
break;
case 'c':
isClient = true;
serverName = optarg;
break;
case 's':
isServer = true;
network = ntohl(inet_addr(optarg));
if (network == INADDR_NONE)
printf("invalid network\n");
break;
case 'm':
mtu = atoi(optarg);
break;
case 'w':
maxPolls = atoi(optarg);
break;
case 'r':
answerPing = true;
break;
case 'q':
changeEchoSeq = true;
break;
case 'i':
changeEchoId = true;
break;
case 'v':
verbose = true;
break;
case 'a':
clientIp = ntohl(inet_addr(optarg));
break;
default:
usage();
return 1;
}
}
mtu -= Echo::headerSize() + Worker::headerSize();
mtu -= Echo::headerSize() + Worker::headerSize();
if (mtu < 68)
{
// RFC 791: Every internet module must be able to forward a datagram of 68 octets without further fragmentation.
printf("mtu too small\n");
return 1;
}
if (mtu < 68)
{
// RFC 791: Every internet module must be able to forward a datagram of 68 octets without further fragmentation.
printf("mtu too small\n");
return 1;
}
if ((isClient == isServer) ||
(isServer && network == INADDR_NONE) ||
(maxPolls < 0 || maxPolls > 255) ||
(isServer && (changeEchoSeq || changeEchoId)))
{
usage();
return 1;
}
if ((isClient == isServer) ||
(isServer && network == INADDR_NONE) ||
(maxPolls < 0 || maxPolls > 255) ||
(isServer && (changeEchoSeq || changeEchoId)))
{
usage();
return 1;
}
if (userName != NULL)
{
passwd *pw = getpwnam(userName);
if (userName != NULL)
{
passwd *pw = getpwnam(userName);
if (pw != NULL)
{
uid = pw->pw_uid;
gid = pw->pw_gid;
}
else
{
syslog(LOG_ERR, "user not found");
return 1;
}
}
if (pw != NULL)
{
uid = pw->pw_uid;
gid = pw->pw_gid;
}
else
{
syslog(LOG_ERR, "user not found");
return 1;
}
}
if (!verbose)
setlogmask(LOG_UPTO(LOG_INFO));
if (!verbose)
setlogmask(LOG_UPTO(LOG_INFO));
try
{
Worker *worker;
try
{
Worker *worker;
if (isServer)
{
worker = new Server(mtu, device, password, network, answerPing, uid, gid, 5000);
}
else
{
uint32_t serverIp = inet_addr(serverName);
if (serverIp == INADDR_NONE)
{
struct hostent* he = gethostbyname(serverName);
if (!he)
{
syslog(LOG_ERR, "gethostbyname: %s", hstrerror(h_errno));
return 1;
}
if (isServer)
{
worker = new Server(mtu, device, password, network, answerPing, uid, gid, 5000);
}
else
{
uint32_t serverIp = inet_addr(serverName);
if (serverIp == INADDR_NONE)
{
struct hostent* he = gethostbyname(serverName);
if (!he)
{
syslog(LOG_ERR, "gethostbyname: %s", hstrerror(h_errno));
return 1;
}
serverIp = *(uint32_t *)he->h_addr;
}
serverIp = *(uint32_t *)he->h_addr;
}
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq, clientIp);
}
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq, clientIp);
}
if (!foreground)
{
syslog(LOG_INFO, "detaching from terminal");
daemon(0, 0);
}
if (!foreground)
{
syslog(LOG_INFO, "detaching from terminal");
daemon(0, 0);
}
worker->run();
}
catch (Exception e)
{
syslog(LOG_ERR, "%s", e.errorMessage());
return 1;
}
worker->run();
}
catch (Exception e)
{
syslog(LOG_ERR, "%s", e.errorMessage());
return 1;
}
return 0;
}

80
osflags
View File

@ -5,48 +5,48 @@ MODE=`echo "$2" | tr "a-z" "A-Z"`
case $1 in
ld)
case $OS in
DARWIN)
if [ "$MODE" == TUNEMU ]; then
echo tunemu.o -lpcap
fi
;;
esac
;;
case $OS in
DARWIN)
if [ "$MODE" == TUNEMU ]; then
echo tunemu.o -lpcap
fi
;;
esac
;;
c)
FLAGS=-D$OS
FLAGS=-D$OS
case $OS in
LINUX)
echo $FLAGS -DHAVE_LINUX_IF_TUN_H
;;
*)
echo $FLAGS
;;
esac
;;
case $OS in
LINUX)
echo $FLAGS -DHAVE_LINUX_IF_TUN_H
;;
*)
echo $FLAGS
;;
esac
;;
dev)
case $OS in
LINUX)
echo tun_dev_linux.c
;;
FREEBSD)
echo tun_dev_freebsd.c
;;
OPENBSD)
echo tun_dev_openbsd.c
;;
DARWIN)
if [ "$MODE" == TUNEMU ]; then
echo tun_dev_darwin_emu.c
else
echo tun_dev_generic.c
fi
;;
*)
echo tun_dev_generic.c
;;
esac
;;
case $OS in
LINUX)
echo tun_dev_linux.c
;;
FREEBSD)
echo tun_dev_freebsd.c
;;
OPENBSD)
echo tun_dev_openbsd.c
;;
DARWIN)
if [ "$MODE" == TUNEMU ]; then
echo tun_dev_darwin_emu.c
else
echo tun_dev_generic.c
fi
;;
*)
echo tun_dev_generic.c
;;
esac
;;
esac

View File

@ -33,15 +33,15 @@ using namespace std;
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)
: Worker(tunnelMtu, deviceName, answerEcho, uid, gid), auth(passphrase)
: Worker(tunnelMtu, deviceName, answerEcho, uid, gid), auth(passphrase)
{
this->network = network & 0xffffff00;
this->pollTimeout = pollTimeout;
this->network = network & 0xffffff00;
this->pollTimeout = pollTimeout;
this->latestAssignedIpOffset = FIRST_ASSIGNED_IP_OFFSET - 1;
tun->setIp(this->network + 1, this->network + 2, true);
tun->setIp(this->network + 1, this->network + 2, true);
dropPrivileges();
dropPrivileges();
}
Server::~Server()
@ -51,269 +51,269 @@ Server::~Server()
void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uint32_t realIp, uint16_t echoId, uint16_t echoSeq)
{
ClientData client;
client.realIp = realIp;
client.maxPolls = 1;
ClientData client;
client.realIp = realIp;
client.maxPolls = 1;
pollReceived(&client, echoId, echoSeq);
pollReceived(&client, echoId, echoSeq);
if (header.type != TunnelHeader::TYPE_CONNECTION_REQUEST || dataLength != sizeof(ClientConnectData))
{
syslog(LOG_DEBUG, "invalid request %s", Utility::formatIp(realIp).c_str());
sendReset(&client);
return;
}
if (header.type != TunnelHeader::TYPE_CONNECTION_REQUEST || dataLength != sizeof(ClientConnectData))
{
syslog(LOG_DEBUG, "invalid request %s", Utility::formatIp(realIp).c_str());
sendReset(&client);
return;
}
ClientConnectData *connectData = (ClientConnectData *)echoReceivePayloadBuffer();
ClientConnectData *connectData = (ClientConnectData *)echoReceivePayloadBuffer();
client.maxPolls = connectData->maxPolls;
client.state = ClientData::STATE_NEW;
client.tunnelIp = reserveTunnelIp(connectData->desiredIp);
client.maxPolls = connectData->maxPolls;
client.state = ClientData::STATE_NEW;
client.tunnelIp = reserveTunnelIp(connectData->desiredIp);
syslog(LOG_DEBUG, "new client: %s (%s)\n", Utility::formatIp(client.realIp).c_str(), Utility::formatIp(client.tunnelIp).c_str());
syslog(LOG_DEBUG, "new client: %s (%s)\n", Utility::formatIp(client.realIp).c_str(), Utility::formatIp(client.tunnelIp).c_str());
if (client.tunnelIp != 0)
{
client.challenge = auth.generateChallenge(CHALLENGE_SIZE);
sendChallenge(&client);
if (client.tunnelIp != 0)
{
client.challenge = auth.generateChallenge(CHALLENGE_SIZE);
sendChallenge(&client);
// add client to list
clientList.push_back(client);
clientRealIpMap[realIp] = clientList.size() - 1;
clientTunnelIpMap[client.tunnelIp] = clientList.size() - 1;
}
else
{
syslog(LOG_WARNING, "server full");
sendEchoToClient(&client, TunnelHeader::TYPE_SERVER_FULL, 0);
}
// add client to list
clientList.push_back(client);
clientRealIpMap[realIp] = clientList.size() - 1;
clientTunnelIpMap[client.tunnelIp] = clientList.size() - 1;
}
else
{
syslog(LOG_WARNING, "server full");
sendEchoToClient(&client, TunnelHeader::TYPE_SERVER_FULL, 0);
}
}
void Server::sendChallenge(ClientData *client)
{
syslog(LOG_DEBUG, "sending challenge to: %s\n", Utility::formatIp(client->realIp).c_str());
syslog(LOG_DEBUG, "sending challenge to: %s\n", Utility::formatIp(client->realIp).c_str());
memcpy(echoSendPayloadBuffer(), &client->challenge[0], client->challenge.size());
sendEchoToClient(client, TunnelHeader::TYPE_CHALLENGE, client->challenge.size());
memcpy(echoSendPayloadBuffer(), &client->challenge[0], client->challenge.size());
sendEchoToClient(client, TunnelHeader::TYPE_CHALLENGE, client->challenge.size());
client->state = ClientData::STATE_CHALLENGE_SENT;
client->state = ClientData::STATE_CHALLENGE_SENT;
}
void Server::removeClient(ClientData *client)
{
syslog(LOG_DEBUG, "removing client: %s (%s)\n", Utility::formatIp(client->realIp).c_str(), Utility::formatIp(client->tunnelIp).c_str());
syslog(LOG_DEBUG, "removing client: %s (%s)\n", Utility::formatIp(client->realIp).c_str(), Utility::formatIp(client->tunnelIp).c_str());
releaseTunnelIp(client->tunnelIp);
releaseTunnelIp(client->tunnelIp);
int nr = clientRealIpMap[client->realIp];
int nr = clientRealIpMap[client->realIp];
clientRealIpMap.erase(client->realIp);
clientTunnelIpMap.erase(client->tunnelIp);
clientRealIpMap.erase(client->realIp);
clientTunnelIpMap.erase(client->tunnelIp);
clientList.erase(clientList.begin() + nr);
clientList.erase(clientList.begin() + nr);
}
void Server::checkChallenge(ClientData *client, int length)
{
Auth::Response rightResponse = auth.getResponse(client->challenge);
Auth::Response rightResponse = auth.getResponse(client->challenge);
if (length != sizeof(Auth::Response) || memcmp(&rightResponse, echoReceivePayloadBuffer(), length) != 0)
{
syslog(LOG_DEBUG, "wrong challenge response\n");
if (length != sizeof(Auth::Response) || memcmp(&rightResponse, echoReceivePayloadBuffer(), length) != 0)
{
syslog(LOG_DEBUG, "wrong challenge response\n");
sendEchoToClient(client, TunnelHeader::TYPE_CHALLENGE_ERROR, 0);
sendEchoToClient(client, TunnelHeader::TYPE_CHALLENGE_ERROR, 0);
removeClient(client);
return;
}
removeClient(client);
return;
}
uint32_t *ip = (uint32_t *)echoSendPayloadBuffer();
*ip = htonl(client->tunnelIp);
uint32_t *ip = (uint32_t *)echoSendPayloadBuffer();
*ip = htonl(client->tunnelIp);
sendEchoToClient(client, TunnelHeader::TYPE_CONNECTION_ACCEPT, sizeof(uint32_t));
sendEchoToClient(client, TunnelHeader::TYPE_CONNECTION_ACCEPT, sizeof(uint32_t));
client->state = ClientData::STATE_ESTABLISHED;
client->state = ClientData::STATE_ESTABLISHED;
syslog(LOG_INFO, "connection established: %s", Utility::formatIp(client->realIp).c_str());
syslog(LOG_INFO, "connection established: %s", Utility::formatIp(client->realIp).c_str());
}
void Server::sendReset(ClientData *client)
{
syslog(LOG_DEBUG, "sending reset: %s", Utility::formatIp(client->realIp).c_str());
sendEchoToClient(client, TunnelHeader::TYPE_RESET_CONNECTION, 0);
syslog(LOG_DEBUG, "sending reset: %s", Utility::formatIp(client->realIp).c_str());
sendEchoToClient(client, TunnelHeader::TYPE_RESET_CONNECTION, 0);
}
bool Server::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
{
if (reply)
return false;
if (reply)
return false;
if (header.magic != Client::magic)
return false;
if (header.magic != Client::magic)
return false;
ClientData *client = getClientByRealIp(realIp);
if (client == NULL)
{
handleUnknownClient(header, dataLength, realIp, id, seq);
return true;
}
ClientData *client = getClientByRealIp(realIp);
if (client == NULL)
{
handleUnknownClient(header, dataLength, realIp, id, seq);
return true;
}
pollReceived(client, id, seq);
pollReceived(client, id, seq);
switch (header.type)
{
case TunnelHeader::TYPE_CONNECTION_REQUEST:
if (client->state == ClientData::STATE_CHALLENGE_SENT)
{
sendChallenge(client);
return true;
}
switch (header.type)
{
case TunnelHeader::TYPE_CONNECTION_REQUEST:
if (client->state == ClientData::STATE_CHALLENGE_SENT)
{
sendChallenge(client);
return true;
}
while (client->pollIds.size() > 1)
client->pollIds.pop();
while (client->pollIds.size() > 1)
client->pollIds.pop();
syslog(LOG_DEBUG, "reconnecting %s", Utility::formatIp(realIp).c_str());
sendReset(client);
removeClient(client);
return true;
case TunnelHeader::TYPE_CHALLENGE_RESPONSE:
if (client->state == ClientData::STATE_CHALLENGE_SENT)
{
checkChallenge(client, dataLength);
return true;
}
break;
case TunnelHeader::TYPE_DATA:
if (client->state == ClientData::STATE_ESTABLISHED)
{
if (dataLength == 0)
{
syslog(LOG_WARNING, "received empty data packet");
return true;
}
syslog(LOG_DEBUG, "reconnecting %s", Utility::formatIp(realIp).c_str());
sendReset(client);
removeClient(client);
return true;
case TunnelHeader::TYPE_CHALLENGE_RESPONSE:
if (client->state == ClientData::STATE_CHALLENGE_SENT)
{
checkChallenge(client, dataLength);
return true;
}
break;
case TunnelHeader::TYPE_DATA:
if (client->state == ClientData::STATE_ESTABLISHED)
{
if (dataLength == 0)
{
syslog(LOG_WARNING, "received empty data packet");
return true;
}
sendToTun(dataLength);
return true;
}
break;
case TunnelHeader::TYPE_POLL:
return true;
}
sendToTun(dataLength);
return true;
}
break;
case TunnelHeader::TYPE_POLL:
return true;
}
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);
return true;
return true;
}
Server::ClientData *Server::getClientByTunnelIp(uint32_t ip)
{
ClientIpMap::iterator clientMapIterator = clientTunnelIpMap.find(ip);
if (clientMapIterator == clientTunnelIpMap.end())
return NULL;
return &clientList[clientMapIterator->second];
ClientIpMap::iterator clientMapIterator = clientTunnelIpMap.find(ip);
if (clientMapIterator == clientTunnelIpMap.end())
return NULL;
return &clientList[clientMapIterator->second];
}
Server::ClientData *Server::getClientByRealIp(uint32_t ip)
{
ClientIpMap::iterator clientMapIterator = clientRealIpMap.find(ip);
if (clientMapIterator == clientRealIpMap.end())
return NULL;
return &clientList[clientMapIterator->second];
ClientIpMap::iterator clientMapIterator = clientRealIpMap.find(ip);
if (clientMapIterator == clientRealIpMap.end())
return NULL;
return &clientList[clientMapIterator->second];
}
void Server::handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp)
{
if (destIp == network + 255) // ignore broadcasts
return;
if (destIp == network + 255) // ignore broadcasts
return;
ClientData *client = getClientByTunnelIp(destIp);
ClientData *client = getClientByTunnelIp(destIp);
if (client == NULL)
{
syslog(LOG_DEBUG, "unknown client: %s\n", Utility::formatIp(destIp).c_str());
return;
}
if (client == NULL)
{
syslog(LOG_DEBUG, "unknown client: %s\n", Utility::formatIp(destIp).c_str());
return;
}
sendEchoToClient(client, TunnelHeader::TYPE_DATA, dataLength);
sendEchoToClient(client, TunnelHeader::TYPE_DATA, dataLength);
}
void Server::pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq)
{
unsigned int maxSavedPolls = client->maxPolls != 0 ? client->maxPolls : 1;
unsigned int maxSavedPolls = client->maxPolls != 0 ? client->maxPolls : 1;
client->pollIds.push(ClientData::EchoId(echoId, echoSeq));
if (client->pollIds.size() > maxSavedPolls)
client->pollIds.pop();
DEBUG_ONLY(printf("poll -> %d\n", client->pollIds.size()));
client->pollIds.push(ClientData::EchoId(echoId, echoSeq));
if (client->pollIds.size() > maxSavedPolls)
client->pollIds.pop();
DEBUG_ONLY(printf("poll -> %d\n", client->pollIds.size()));
if (client->pendingPackets.size() > 0)
{
Packet &packet = client->pendingPackets.front();
memcpy(echoSendPayloadBuffer(), &packet.data[0], packet.data.size());
client->pendingPackets.pop();
if (client->pendingPackets.size() > 0)
{
Packet &packet = client->pendingPackets.front();
memcpy(echoSendPayloadBuffer(), &packet.data[0], packet.data.size());
client->pendingPackets.pop();
DEBUG_ONLY(printf("pending packet: %d bytes\n", packet.data.size()));
sendEchoToClient(client, packet.type, packet.data.size());
}
DEBUG_ONLY(printf("pending packet: %d bytes\n", 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)
{
if (client->maxPolls == 0)
{
sendEcho(magic, type, dataLength, client->realIp, true, client->pollIds.front().id, client->pollIds.front().seq);
return;
}
if (client->maxPolls == 0)
{
sendEcho(magic, type, dataLength, client->realIp, true, client->pollIds.front().id, client->pollIds.front().seq);
return;
}
if (client->pollIds.size() != 0)
{
ClientData::EchoId echoId = client->pollIds.front();
client->pollIds.pop();
if (client->pollIds.size() != 0)
{
ClientData::EchoId echoId = client->pollIds.front();
client->pollIds.pop();
DEBUG_ONLY(printf("sending -> %d\n", client->pollIds.size()));
sendEcho(magic, type, dataLength, client->realIp, true, echoId.id, echoId.seq);
return;
}
DEBUG_ONLY(printf("sending -> %d\n", client->pollIds.size()));
sendEcho(magic, type, dataLength, client->realIp, true, echoId.id, echoId.seq);
return;
}
if (client->pendingPackets.size() == MAX_BUFFERED_PACKETS)
{
client->pendingPackets.pop();
syslog(LOG_WARNING, "packet dropped to %s", Utility::formatIp(client->tunnelIp).c_str());
}
if (client->pendingPackets.size() == MAX_BUFFERED_PACKETS)
{
client->pendingPackets.pop();
syslog(LOG_WARNING, "packet dropped to %s", Utility::formatIp(client->tunnelIp).c_str());
}
DEBUG_ONLY(printf("packet queued: %d bytes\n", dataLength));
DEBUG_ONLY(printf("packet queued: %d bytes\n", dataLength));
client->pendingPackets.push(Packet());
Packet &packet = client->pendingPackets.back();
packet.type = type;
packet.data.resize(dataLength);
memcpy(&packet.data[0], echoReceivePayloadBuffer(), dataLength);
client->pendingPackets.push(Packet());
Packet &packet = client->pendingPackets.back();
packet.type = type;
packet.data.resize(dataLength);
memcpy(&packet.data[0], echoReceivePayloadBuffer(), dataLength);
}
void Server::releaseTunnelIp(uint32_t tunnelIp)
{
usedIps.erase(tunnelIp);
usedIps.erase(tunnelIp);
}
void Server::handleTimeout()
{
for (int i = 0; i < clientList.size(); i++)
{
ClientData *client = &clientList[i];
for (int i = 0; i < clientList.size(); i++)
{
ClientData *client = &clientList[i];
if (client->lastActivity + KEEP_ALIVE_INTERVAL * 2 < now)
{
syslog(LOG_DEBUG, "client timeout: %s\n", Utility::formatIp(client->realIp).c_str());
removeClient(client);
i--;
}
}
if (client->lastActivity + KEEP_ALIVE_INTERVAL * 2 < now)
{
syslog(LOG_DEBUG, "client timeout: %s\n", Utility::formatIp(client->realIp).c_str());
removeClient(client);
i--;
}
}
setTimeout(KEEP_ALIVE_INTERVAL);
setTimeout(KEEP_ALIVE_INTERVAL);
}
uint32_t Server::reserveTunnelIp(uint32_t desiredIp)
@ -339,16 +339,16 @@ uint32_t Server::reserveTunnelIp(uint32_t desiredIp)
}
}
if (!ipAvailable)
return 0;
if (!ipAvailable)
return 0;
usedIps.insert(network + latestAssignedIpOffset);
return network + latestAssignedIpOffset;
usedIps.insert(network + latestAssignedIpOffset);
return network + latestAssignedIpOffset;
}
void Server::run()
{
setTimeout(KEEP_ALIVE_INTERVAL);
setTimeout(KEEP_ALIVE_INTERVAL);
Worker::run();
Worker::run();
}

120
server.h
View File

@ -31,96 +31,96 @@
class Server : public Worker
{
public:
Server(int tunnelMtu, const char *deviceName, const char *passphrase, uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout);
virtual ~Server();
Server(int tunnelMtu, const char *deviceName, const char *passphrase, uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout);
virtual ~Server();
// change some time:
// struct __attribute__ ((__packed__)) ClientConnectData
struct ClientConnectData
{
uint8_t maxPolls;
struct ClientConnectData
{
uint8_t maxPolls;
uint32_t desiredIp;
};
};
static const Worker::TunnelHeader::Magic magic;
static const Worker::TunnelHeader::Magic magic;
protected:
struct Packet
{
int type;
std::vector<char> data;
};
struct Packet
{
int type;
std::vector<char> data;
};
struct ClientData
{
enum State
{
STATE_NEW,
STATE_CHALLENGE_SENT,
STATE_ESTABLISHED
};
struct ClientData
{
enum State
{
STATE_NEW,
STATE_CHALLENGE_SENT,
STATE_ESTABLISHED
};
struct EchoId
{
EchoId(uint16_t id, uint16_t seq) { this->id = id; this->seq = seq; }
struct EchoId
{
EchoId(uint16_t id, uint16_t seq) { this->id = id; this->seq = seq; }
uint16_t id;
uint16_t seq;
};
uint16_t id;
uint16_t seq;
};
uint32_t realIp;
uint32_t tunnelIp;
uint32_t realIp;
uint32_t tunnelIp;
std::queue<Packet> pendingPackets;
std::queue<Packet> pendingPackets;
int maxPolls;
std::queue<EchoId> pollIds;
Time lastActivity;
int maxPolls;
std::queue<EchoId> pollIds;
Time lastActivity;
State state;
State state;
Auth::Challenge challenge;
};
Auth::Challenge challenge;
};
typedef std::vector<ClientData> ClientList;
typedef std::map<uint32_t, int> ClientIpMap;
typedef std::vector<ClientData> ClientList;
typedef std::map<uint32_t, int> ClientIpMap;
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
virtual void handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp);
virtual void handleTimeout();
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
virtual void handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp);
virtual void handleTimeout();
virtual void run();
virtual void run();
void serveTun(ClientData *client);
void serveTun(ClientData *client);
void handleUnknownClient(const TunnelHeader &header, int dataLength, uint32_t realIp, uint16_t echoId, uint16_t echoSeq);
void removeClient(ClientData *client);
void handleUnknownClient(const TunnelHeader &header, int dataLength, uint32_t realIp, uint16_t echoId, uint16_t echoSeq);
void removeClient(ClientData *client);
void sendChallenge(ClientData *client);
void checkChallenge(ClientData *client, int dataLength);
void sendReset(ClientData *client);
void sendChallenge(ClientData *client);
void checkChallenge(ClientData *client, int dataLength);
void sendReset(ClientData *client);
void sendEchoToClient(ClientData *client, int type, int dataLength);
void sendEchoToClient(ClientData *client, int type, int dataLength);
void pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq);
void pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq);
uint32_t reserveTunnelIp(uint32_t desiredIp);
void releaseTunnelIp(uint32_t tunnelIp);
uint32_t reserveTunnelIp(uint32_t desiredIp);
void releaseTunnelIp(uint32_t tunnelIp);
ClientData *getClientByTunnelIp(uint32_t ip);
ClientData *getClientByRealIp(uint32_t ip);
ClientData *getClientByTunnelIp(uint32_t ip);
ClientData *getClientByRealIp(uint32_t ip);
Auth auth;
Auth auth;
uint32_t network;
std::set<uint32_t> usedIps;
uint32_t network;
std::set<uint32_t> usedIps;
uint32_t latestAssignedIpOffset;
Time pollTimeout;
Time pollTimeout;
ClientList clientList;
ClientIpMap clientRealIpMap;
ClientIpMap clientTunnelIpMap;
ClientList clientList;
ClientIpMap clientRealIpMap;
ClientIpMap clientTunnelIpMap;
};
#endif

View File

@ -23,63 +23,63 @@ const Time Time::ZERO = Time(0);
Time::Time(int ms)
{
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000;
}
Time Time::operator-(const Time &other) const
{
Time result;
result.tv.tv_sec = tv.tv_sec - other.tv.tv_sec;
result.tv.tv_usec = tv.tv_usec - other.tv.tv_usec;
if (result.tv.tv_usec < 0)
{
result.tv.tv_usec += 1000000;
result.tv.tv_sec -= 1;
}
return result;
Time result;
result.tv.tv_sec = tv.tv_sec - other.tv.tv_sec;
result.tv.tv_usec = tv.tv_usec - other.tv.tv_usec;
if (result.tv.tv_usec < 0)
{
result.tv.tv_usec += 1000000;
result.tv.tv_sec -= 1;
}
return result;
}
Time Time::operator+(const Time &other) const
{
Time result;
result.tv.tv_sec = tv.tv_sec + other.tv.tv_sec;
result.tv.tv_usec = tv.tv_usec + other.tv.tv_usec;
if (result.tv.tv_usec >= 1000000)
{
result.tv.tv_usec -= 1000000;
result.tv.tv_sec += 1;
}
return result;
Time result;
result.tv.tv_sec = tv.tv_sec + other.tv.tv_sec;
result.tv.tv_usec = tv.tv_usec + other.tv.tv_usec;
if (result.tv.tv_usec >= 1000000)
{
result.tv.tv_usec -= 1000000;
result.tv.tv_sec += 1;
}
return result;
}
bool Time::operator==(const Time &other) const
{
return tv.tv_sec != other.tv.tv_sec ? false : tv.tv_usec == other.tv.tv_usec;
return tv.tv_sec != other.tv.tv_sec ? false : tv.tv_usec == other.tv.tv_usec;
}
bool Time::operator!=(const Time &other) const
{
return tv.tv_sec != other.tv.tv_sec ? true : tv.tv_usec != other.tv.tv_usec;
return tv.tv_sec != other.tv.tv_sec ? true : tv.tv_usec != other.tv.tv_usec;
}
bool Time::operator<(const Time &other) const
{
return tv.tv_sec != other.tv.tv_sec ? tv.tv_sec < other.tv.tv_sec : tv.tv_usec < other.tv.tv_usec;
return tv.tv_sec != other.tv.tv_sec ? tv.tv_sec < other.tv.tv_sec : tv.tv_usec < other.tv.tv_usec;
}
bool Time::operator>(const Time &other) const
{
return tv.tv_sec != other.tv.tv_sec ? tv.tv_sec > other.tv.tv_sec : tv.tv_usec > other.tv.tv_usec;
return tv.tv_sec != other.tv.tv_sec ? tv.tv_sec > other.tv.tv_sec : tv.tv_usec > other.tv.tv_usec;
}
Time Time::now()
{
Time result;
gettimeofday(&result.tv, 0);
return result;
Time result;
gettimeofday(&result.tv, 0);
return result;
}

24
time.h
View File

@ -25,24 +25,24 @@
class Time
{
public:
Time() { tv.tv_sec = 0; tv.tv_usec = 0; };
Time(int ms);
Time() { tv.tv_sec = 0; tv.tv_usec = 0; };
Time(int ms);
timeval &getTimeval() { return tv; }
timeval &getTimeval() { return tv; }
Time operator+(const Time &other) const;
Time operator-(const Time &other) const;
Time operator+(const Time &other) const;
Time operator-(const Time &other) const;
bool operator!=(const Time &other) const;
bool operator==(const Time &other) const;
bool operator<(const Time &other) const;
bool operator>(const Time &other) const;
bool operator!=(const Time &other) const;
bool operator==(const Time &other) const;
bool operator<(const Time &other) const;
bool operator>(const Time &other) const;
static Time now();
static Time now();
static const Time ZERO;
static const Time ZERO;
protected:
timeval tv;
timeval tv;
};
#endif

80
tun.cpp
View File

@ -37,77 +37,77 @@ using namespace std;
Tun::Tun(const char *device, int mtu)
{
this->mtu = mtu;
this->mtu = mtu;
if (device != NULL)
{
strncpy(this->device, device, VTUN_DEV_LEN);
this->device[VTUN_DEV_LEN] = 0;
}
else
this->device[0] = 0;
if (device != NULL)
{
strncpy(this->device, device, VTUN_DEV_LEN);
this->device[VTUN_DEV_LEN] = 0;
}
else
this->device[0] = 0;
fd = tun_open(this->device);
if (fd == -1)
throw Exception("could not create tunnel device");
fd = tun_open(this->device);
if (fd == -1)
throw Exception("could not create tunnel device");
char cmdline[512];
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s mtu %u", this->device, mtu);
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device mtu");
char cmdline[512];
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s mtu %u", this->device, mtu);
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device mtu");
}
Tun::~Tun()
{
tun_close(fd, device);
tun_close(fd, device);
}
void Tun::setIp(uint32_t ip, uint32_t destIp, bool includeSubnet)
{
char cmdline[512];
string ips = Utility::formatIp(ip);
string destIps = Utility::formatIp(destIp);
char cmdline[512];
string ips = Utility::formatIp(ip);
string destIps = Utility::formatIp(destIp);
#ifdef LINUX
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s netmask 255.255.255.0", device, ips.c_str());
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s netmask 255.255.255.0", device, ips.c_str());
#else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str());
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str());
#endif
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device ip address");
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not set tun device ip address");
#ifndef LINUX
if (includeSubnet)
{
snprintf(cmdline, sizeof(cmdline), "/sbin/route add %s/24 %s", destIps.c_str(), destIps.c_str());
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not add route");
}
if (includeSubnet)
{
snprintf(cmdline, sizeof(cmdline), "/sbin/route add %s/24 %s", destIps.c_str(), destIps.c_str());
if (system(cmdline) != 0)
syslog(LOG_ERR, "could not add route");
}
#endif
}
void Tun::write(const char *buffer, int length)
{
if (tun_write(fd, (char *)buffer, length) == -1)
syslog(LOG_ERR, "error writing %d bytes to tun: %s", length, strerror(errno));
if (tun_write(fd, (char *)buffer, length) == -1)
syslog(LOG_ERR, "error writing %d bytes to tun: %s", length, strerror(errno));
}
int Tun::read(char *buffer)
{
int length = tun_read(fd, buffer, mtu);
if (length == -1)
syslog(LOG_ERR, "error reading from tun: %s", strerror(errno));
return length;
int length = tun_read(fd, buffer, mtu);
if (length == -1)
syslog(LOG_ERR, "error reading from tun: %s", strerror(errno));
return length;
}
int Tun::read(char *buffer, uint32_t &sourceIp, uint32_t &destIp)
{
int length = read(buffer);
int length = read(buffer);
IpHeader *header = (IpHeader *)buffer;
sourceIp = ntohl(header->ip_src.s_addr);
destIp = ntohl(header->ip_dst.s_addr);
IpHeader *header = (IpHeader *)buffer;
sourceIp = ntohl(header->ip_src.s_addr);
destIp = ntohl(header->ip_dst.s_addr);
return length;
return length;
}

20
tun.h
View File

@ -28,22 +28,22 @@
class Tun
{
public:
Tun(const char *device, int mtu);
~Tun();
Tun(const char *device, int mtu);
~Tun();
int getFd() { return fd; }
int getFd() { return fd; }
int read(char *buffer);
int read(char *buffer, uint32_t &sourceIp, uint32_t &destIp);
int read(char *buffer);
int read(char *buffer, uint32_t &sourceIp, uint32_t &destIp);
void write(const char *buffer, int length);
void write(const char *buffer, int length);
void setIp(uint32_t ip, uint32_t destIp, bool includeSubnet);
void setIp(uint32_t ip, uint32_t destIp, bool includeSubnet);
protected:
char device[VTUN_DEV_LEN];
char device[VTUN_DEV_LEN];
int mtu;
int fd;
int mtu;
int fd;
};
#endif

View File

@ -20,8 +20,8 @@
extern "C"
{
int tun_open(char *dev);
int tun_close(int fd, char *dev);
int tun_write(int fd, char *buf, int len);
int tun_read(int fd, char *buf, int len);
int tun_open(char *dev);
int tun_close(int fd, char *dev);
int tun_write(int fd, char *buf, int len);
int tun_read(int fd, char *buf, int len);
}

View File

@ -22,23 +22,23 @@
int tun_open(char *dev)
{
int fd = tunemu_open(dev);
if (fd < 0)
syslog(LOG_ERR, tunemu_error);
return fd;
int fd = tunemu_open(dev);
if (fd < 0)
syslog(LOG_ERR, tunemu_error);
return fd;
}
int tun_close(int fd, char *dev)
{
return tunemu_close(fd);
return tunemu_close(fd);
}
int tun_write(int fd, char *buf, int len)
{
return tunemu_write(fd, buf, len);
return tunemu_write(fd, buf, len);
}
int tun_read(int fd, char *buf, int len)
{
return tunemu_read(fd, buf, len);
return tunemu_read(fd, buf, len);
}

View File

@ -60,9 +60,9 @@ int tun_open(char *dev)
if( fd > -1 ){
i=0;
/* Disable extended modes */
ioctl(fd, TUNSLMODE, &i);
ioctl(fd, TUNSLMODE, &i);
ioctl(fd, TUNSIFHEAD, &i);
}
}
return fd;
}

View File

@ -62,11 +62,11 @@ static int tun_open_common0(char *dev, int istun)
}
else if (errno != ENOENT)
err = errno;
else if (i) /* don't try all 256 devices */
else if (i) /* don't try all 256 devices */
break;
}
if (err)
errno = err;
errno = err;
return -1;
}
@ -97,9 +97,9 @@ static int tun_open_common(char *dev, int istun)
if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
if (errno == EBADFD) {
/* Try old ioctl */
if (ioctl(fd, OTUNSETIFF, (void *) &ifr) < 0)
goto failed;
/* Try old ioctl */
if (ioctl(fd, OTUNSETIFF, (void *) &ifr) < 0)
goto failed;
} else
goto failed;
}

View File

@ -74,7 +74,7 @@ int tun_open(char *dev)
char *ptr;
if( *dev ){
ptr = dev;
ptr = dev;
while( *ptr && !isdigit((int)*ptr) ) ptr++;
ppa = atoi(ptr);
}

View File

@ -26,18 +26,18 @@ using namespace std;
string Utility::formatIp(uint32_t ip)
{
char buffer[16];
sprintf(buffer, "%d.%d.%d.%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
return buffer;
char buffer[16];
sprintf(buffer, "%d.%d.%d.%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
return buffer;
}
int Utility::rand()
{
static bool init = false;
if (!init)
{
init = true;
srand(time(NULL));
}
return ::rand();
static bool init = false;
if (!init)
{
init = true;
srand(time(NULL));
}
return ::rand();
}

View File

@ -26,8 +26,8 @@
class Utility
{
public:
static std::string formatIp(uint32_t ip);
static int rand();
static std::string formatIp(uint32_t ip);
static int rand();
};
#endif

View File

@ -30,169 +30,169 @@ using namespace std;
Worker::TunnelHeader::Magic::Magic(const char *magic)
{
memset(data, 0, sizeof(data));
strncpy(data, magic, sizeof(data));
memset(data, 0, sizeof(data));
strncpy(data, magic, sizeof(data));
}
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;
}
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)
{
this->tunnelMtu = tunnelMtu;
this->answerEcho = answerEcho;
this->uid = uid;
this->gid = gid;
this->privilegesDropped = false;
this->tunnelMtu = tunnelMtu;
this->answerEcho = answerEcho;
this->uid = uid;
this->gid = gid;
this->privilegesDropped = false;
echo = NULL;
tun = NULL;
echo = NULL;
tun = NULL;
try
{
echo = new Echo(tunnelMtu + sizeof(TunnelHeader));
tun = new Tun(deviceName, tunnelMtu);
}
catch (...)
{
delete echo;
delete tun;
try
{
echo = new Echo(tunnelMtu + sizeof(TunnelHeader));
tun = new Tun(deviceName, tunnelMtu);
}
catch (...)
{
delete echo;
delete tun;
throw;
}
throw;
}
}
Worker::~Worker()
{
delete echo;
delete tun;
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())
throw Exception("packet too big");
if (length > payloadBufferSize())
throw Exception("packet too big");
TunnelHeader *header = (TunnelHeader *)echo->sendPayloadBuffer();
header->magic = magic;
header->type = type;
TunnelHeader *header = (TunnelHeader *)echo->sendPayloadBuffer();
header->magic = magic;
header->type = type;
DEBUG_ONLY(printf("sending: type %d, length %d, id %d, seq %d\n", type, length, id, seq));
DEBUG_ONLY(printf("sending: type %d, length %d, id %d, seq %d\n", type, length, id, seq));
echo->send(length + sizeof(TunnelHeader), realIp, reply, id, seq);
echo->send(length + sizeof(TunnelHeader), realIp, reply, id, seq);
}
void Worker::sendToTun(int length)
{
tun->write(echoReceivePayloadBuffer(), length);
tun->write(echoReceivePayloadBuffer(), length);
}
void Worker::setTimeout(Time delta)
{
nextTimeout = now + delta;
nextTimeout = now + delta;
}
void Worker::run()
{
now = Time::now();
alive = true;
now = Time::now();
alive = true;
int maxFd = echo->getFd() > tun->getFd() ? echo->getFd() : tun->getFd();
int maxFd = echo->getFd() > tun->getFd() ? echo->getFd() : tun->getFd();
while (alive)
{
fd_set fs;
Time timeout;
while (alive)
{
fd_set fs;
Time timeout;
FD_ZERO(&fs);
FD_SET(tun->getFd(), &fs);
FD_SET(echo->getFd(), &fs);
FD_ZERO(&fs);
FD_SET(tun->getFd(), &fs);
FD_SET(echo->getFd(), &fs);
if (nextTimeout != Time::ZERO)
{
timeout = nextTimeout - now;
if (timeout < Time::ZERO)
timeout = Time::ZERO;
}
if (nextTimeout != Time::ZERO)
{
timeout = nextTimeout - now;
if (timeout < Time::ZERO)
timeout = Time::ZERO;
}
// wait for data or timeout
int result = select(maxFd + 1 , &fs, NULL, NULL, nextTimeout != Time::ZERO ? &timeout.getTimeval() : NULL);
if (result == -1)
throw Exception("select", true);
now = Time::now();
// wait for data or timeout
int result = select(maxFd + 1 , &fs, NULL, NULL, nextTimeout != Time::ZERO ? &timeout.getTimeval() : NULL);
if (result == -1)
throw Exception("select", true);
now = Time::now();
// timeout
if (result == 0)
{
nextTimeout = Time::ZERO;
handleTimeout();
continue;
}
// timeout
if (result == 0)
{
nextTimeout = Time::ZERO;
handleTimeout();
continue;
}
// icmp data
if (FD_ISSET(echo->getFd(), &fs))
{
bool reply;
uint16_t id, seq;
uint32_t ip;
// icmp data
if (FD_ISSET(echo->getFd(), &fs))
{
bool reply;
uint16_t id, seq;
uint32_t ip;
int dataLength = echo->receive(ip, reply, id, seq);
if (dataLength != -1)
{
bool valid = dataLength >= sizeof(TunnelHeader);
int dataLength = echo->receive(ip, reply, id, seq);
if (dataLength != -1)
{
bool valid = dataLength >= sizeof(TunnelHeader);
if (valid)
{
TunnelHeader *header = (TunnelHeader *)echo->receivePayloadBuffer();
if (valid)
{
TunnelHeader *header = (TunnelHeader *)echo->receivePayloadBuffer();
DEBUG_ONLY(printf("received: type %d, length %d, id %d, seq %d\n", header->type, dataLength - sizeof(TunnelHeader), id, seq));
DEBUG_ONLY(printf("received: type %d, length %d, id %d, seq %d\n", header->type, dataLength - sizeof(TunnelHeader), id, seq));
valid = handleEchoData(*header, dataLength - sizeof(TunnelHeader), ip, reply, id, seq);
}
valid = handleEchoData(*header, dataLength - sizeof(TunnelHeader), ip, reply, id, seq);
}
if (!valid && !reply && answerEcho)
{
memcpy(echo->sendPayloadBuffer(), echo->receivePayloadBuffer(), dataLength);
echo->send(dataLength, ip, true, id, seq);
}
}
}
if (!valid && !reply && answerEcho)
{
memcpy(echo->sendPayloadBuffer(), echo->receivePayloadBuffer(), dataLength);
echo->send(dataLength, ip, true, id, seq);
}
}
}
// data from tun
if (FD_ISSET(tun->getFd(), &fs))
{
uint32_t sourceIp, destIp;
// data from tun
if (FD_ISSET(tun->getFd(), &fs))
{
uint32_t sourceIp, destIp;
int dataLength = tun->read(echoSendPayloadBuffer(), sourceIp, destIp);
int dataLength = tun->read(echoSendPayloadBuffer(), sourceIp, destIp);
if (dataLength == 0)
throw Exception("tunnel closed");
if (dataLength == 0)
throw Exception("tunnel closed");
if (dataLength != -1)
handleTunData(dataLength, sourceIp, destIp);
}
}
}
}
}
void Worker::dropPrivileges()
{
if (uid <= 0 || privilegesDropped)
return;
if (uid <= 0 || privilegesDropped)
return;
syslog(LOG_INFO, "dropping privileges");
syslog(LOG_INFO, "dropping privileges");
if (setgid(gid) == -1)
throw Exception("setgid", true);
if (setgid(gid) == -1)
throw Exception("setgid", true);
if (setuid(uid) == -1)
throw Exception("setuid", true);
if (setuid(uid) == -1)
throw Exception("setuid", true);
privilegesDropped = true;
privilegesDropped = true;
}

102
worker.h
View File

@ -29,76 +29,76 @@
class Worker
{
public:
Worker(int tunnelMtu, const char *deviceName, bool answerEcho, uid_t uid, gid_t gid);
virtual ~Worker();
Worker(int tunnelMtu, const char *deviceName, bool answerEcho, uid_t uid, gid_t gid);
virtual ~Worker();
virtual void run();
virtual void run();
static int headerSize() { return sizeof(TunnelHeader); }
static int headerSize() { return sizeof(TunnelHeader); }
protected:
struct TunnelHeader
{
struct Magic
{
Magic() { }
Magic(const char *magic);
struct TunnelHeader
{
struct Magic
{
Magic() { }
Magic(const char *magic);
bool operator==(const Magic &other) const;
bool operator!=(const Magic &other) const;
bool operator==(const Magic &other) const;
bool operator!=(const Magic &other) const;
char data[4];
};
char data[4];
};
Magic magic;
uint8_t type;
Magic magic;
uint8_t type;
enum Type
{
TYPE_RESET_CONNECTION = 1,
TYPE_CONNECTION_REQUEST = 2,
TYPE_CHALLENGE = 3,
TYPE_CHALLENGE_RESPONSE = 4,
TYPE_CONNECTION_ACCEPT = 5,
TYPE_CHALLENGE_ERROR = 6,
TYPE_DATA = 7,
TYPE_POLL = 8,
TYPE_SERVER_FULL = 9
};
}; // size = 5
enum Type
{
TYPE_RESET_CONNECTION = 1,
TYPE_CONNECTION_REQUEST = 2,
TYPE_CHALLENGE = 3,
TYPE_CHALLENGE_RESPONSE = 4,
TYPE_CONNECTION_ACCEPT = 5,
TYPE_CHALLENGE_ERROR = 6,
TYPE_DATA = 7,
TYPE_POLL = 8,
TYPE_SERVER_FULL = 9
};
}; // size = 5
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq) { return true; }
virtual void handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp) { } // to echoSendPayloadBuffer
virtual void handleTimeout() { }
virtual bool handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq) { return true; }
virtual void handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp) { } // to echoSendPayloadBuffer
virtual void handleTimeout() { }
void sendEcho(const TunnelHeader::Magic &magic, int type, int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
void sendToTun(int length); // from echoReceivePayloadBuffer
void sendEcho(const TunnelHeader::Magic &magic, int type, int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
void sendToTun(int length); // from echoReceivePayloadBuffer
void setTimeout(Time delta);
void setTimeout(Time delta);
char *echoSendPayloadBuffer() { return echo->sendPayloadBuffer() + sizeof(TunnelHeader); }
char *echoReceivePayloadBuffer() { return echo->receivePayloadBuffer() + sizeof(TunnelHeader); }
char *echoSendPayloadBuffer() { return echo->sendPayloadBuffer() + sizeof(TunnelHeader); }
char *echoReceivePayloadBuffer() { return echo->receivePayloadBuffer() + sizeof(TunnelHeader); }
int payloadBufferSize() { return tunnelMtu; }
int payloadBufferSize() { return tunnelMtu; }
void dropPrivileges();
void dropPrivileges();
Echo *echo;
Tun *tun;
bool alive;
bool answerEcho;
int tunnelMtu;
int maxTunnelHeaderSize;
uid_t uid;
gid_t gid;
Echo *echo;
Tun *tun;
bool alive;
bool answerEcho;
int tunnelMtu;
int maxTunnelHeaderSize;
uid_t uid;
gid_t gid;
bool privilegesDropped;
bool privilegesDropped;
Time now;
Time now;
private:
int readIcmpData(int *realIp, int *id, int *seq);
int readIcmpData(int *realIp, int *id, int *seq);
Time nextTimeout;
Time nextTimeout;
};
#endif