mirror of
https://github.com/norohind/hans.git
synced 2025-04-15 06:00:33 +03:00
improved ip assignment
more stable error handling
This commit is contained in:
parent
6f211f8ee9
commit
98327991f1
25
client.cpp
25
client.cpp
@ -31,11 +31,14 @@ using namespace std;
|
||||
|
||||
const Worker::TunnelHeader::Magic Client::magic("hanc");
|
||||
|
||||
Client::Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, int maxPolls,
|
||||
const char *passphrase, uid_t uid, gid_t gid, bool changeEchoId, bool changeEchoSeq)
|
||||
: Worker(tunnelMtu, deviceName, false, uid, gid), auth(passphrase)
|
||||
Client::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)
|
||||
: Worker(tunnelMtu, deviceName, false, uid, gid), auth(passphrase)
|
||||
{
|
||||
this->serverIp = serverIp;
|
||||
this->clientIp = INADDR_NONE;
|
||||
this->desiredIp = desiredIp;
|
||||
this->maxPolls = maxPolls;
|
||||
this->nextEchoId = Utility::rand();
|
||||
this->changeEchoId = changeEchoId;
|
||||
@ -47,13 +50,14 @@ Client::Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, int max
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Client::sendConnectionRequest()
|
||||
{
|
||||
Server::ClientConnectData *connectData = (Server::ClientConnectData *)echoSendPayloadBuffer();
|
||||
connectData->maxPolls = maxPolls;
|
||||
connectData->desiredIp = desiredIp;
|
||||
|
||||
syslog(LOG_DEBUG, "sending connection request");
|
||||
|
||||
@ -97,9 +101,6 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
|
||||
case TunnelHeader::TYPE_RESET_CONNECTION:
|
||||
syslog(LOG_DEBUG, "reset reveiced");
|
||||
|
||||
if (privilegesDropped)
|
||||
throw Exception("cannot reconnect without root privileges");
|
||||
|
||||
sendConnectionRequest();
|
||||
return true;
|
||||
case TunnelHeader::TYPE_SERVER_FULL:
|
||||
@ -128,7 +129,15 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
|
||||
syslog(LOG_INFO, "connection established");
|
||||
|
||||
uint32_t ip = ntohl(*(uint32_t *)echoReceivePayloadBuffer());
|
||||
tun->setIp(ip, (ip & 0xffffff00) + 1, false);
|
||||
if (ip != clientIp)
|
||||
{
|
||||
if (privilegesDropped)
|
||||
throw Exception("could not get the same ip address, so root privileges are required to change it");
|
||||
|
||||
clientIp = ip;
|
||||
desiredIp = ip;
|
||||
tun->setIp(ip, (ip & 0xffffff00) + 1, false);
|
||||
}
|
||||
state = STATE_ESTABLISHED;
|
||||
|
||||
dropPrivileges();
|
||||
|
7
client.h
7
client.h
@ -28,8 +28,9 @@
|
||||
class Client : public Worker
|
||||
{
|
||||
public:
|
||||
Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, int maxPolls,
|
||||
const char *passphrase, uid_t uid, gid_t gid, bool changeEchoId, bool changeEchoSeq);
|
||||
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 void run();
|
||||
@ -59,6 +60,8 @@ protected:
|
||||
Auth auth;
|
||||
|
||||
uint32_t serverIp;
|
||||
uint32_t clientIp;
|
||||
uint32_t desiredIp;
|
||||
|
||||
int maxPolls;
|
||||
int pollTimeoutNr;
|
||||
|
10
echo.cpp
10
echo.cpp
@ -26,6 +26,9 @@
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef ip IpHeader;
|
||||
|
||||
@ -72,7 +75,7 @@ void Echo::send(int payloadLength, uint32_t realIp, bool reply, uint16_t id, uin
|
||||
|
||||
int result = sendto(fd, sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
|
||||
if (result == -1)
|
||||
throw Exception("sendto", true);
|
||||
syslog(LOG_ERR, "error sending icmp packet: %s", strerror(errno));
|
||||
}
|
||||
|
||||
int Echo::receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq)
|
||||
@ -82,7 +85,10 @@ int Echo::receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq)
|
||||
|
||||
int dataLength = recvfrom(fd, receiveBuffer, bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
|
||||
if (dataLength == -1)
|
||||
throw Exception("recvfrom", true);
|
||||
{
|
||||
syslog(LOG_ERR, "error receiving icmp packet: %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader))
|
||||
return -1;
|
||||
|
13
main.cpp
13
main.cpp
@ -36,7 +36,7 @@ void usage()
|
||||
printf(
|
||||
"Hans - IP over ICMP version 0.3.1\n\n"
|
||||
"RUN AS SERVER\n"
|
||||
" hans -s network [-fvr] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu]\n\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"
|
||||
@ -54,7 +54,8 @@ void usage()
|
||||
" -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"
|
||||
" -q Change the echo sequence number for every echo request.\n"
|
||||
" -a ip Try to get assigned the given tunnel ip address.\n"
|
||||
);
|
||||
}
|
||||
|
||||
@ -70,6 +71,7 @@ int main(int argc, char *argv[])
|
||||
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;
|
||||
@ -80,7 +82,7 @@ int main(int argc, char *argv[])
|
||||
openlog(argv[0], LOG_PERROR, LOG_DAEMON);
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "fru:d:p:s:c:m:w:qiv")) != -1)
|
||||
while ((c = getopt(argc, argv, "fru:d:p:s:c:m:w:qiva:")) != -1)
|
||||
{
|
||||
switch(c) {
|
||||
case 'f':
|
||||
@ -124,6 +126,9 @@ int main(int argc, char *argv[])
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'a':
|
||||
clientIp = ntohl(inet_addr(optarg));
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
return 1;
|
||||
@ -190,7 +195,7 @@ int main(int argc, char *argv[])
|
||||
serverIp = *(uint32_t *)he->h_addr;
|
||||
}
|
||||
|
||||
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq);
|
||||
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq, clientIp);
|
||||
}
|
||||
|
||||
if (!foreground)
|
||||
|
43
server.cpp
43
server.cpp
@ -28,6 +28,8 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define FIRST_ASSIGNED_IP_OFFSET 100
|
||||
|
||||
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)
|
||||
@ -35,6 +37,7 @@ Server::Server(int tunnelMtu, const char *deviceName, const char *passphrase, ui
|
||||
{
|
||||
this->network = network & 0xffffff00;
|
||||
this->pollTimeout = pollTimeout;
|
||||
this->latestAssignedIpOffset = FIRST_ASSIGNED_IP_OFFSET - 1;
|
||||
|
||||
tun->setIp(this->network + 1, this->network + 2, true);
|
||||
|
||||
@ -65,7 +68,7 @@ void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uin
|
||||
|
||||
client.maxPolls = connectData->maxPolls;
|
||||
client.state = ClientData::STATE_NEW;
|
||||
client.tunnelIp = reserveTunnelIp();
|
||||
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());
|
||||
|
||||
@ -186,7 +189,6 @@ bool Server::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
|
||||
if (dataLength == 0)
|
||||
{
|
||||
syslog(LOG_WARNING, "received empty data packet");
|
||||
throw 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -294,7 +296,7 @@ void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
|
||||
|
||||
void Server::releaseTunnelIp(uint32_t tunnelIp)
|
||||
{
|
||||
usedIps.remove(tunnelIp);
|
||||
usedIps.erase(tunnelIp);
|
||||
}
|
||||
|
||||
void Server::handleTimeout()
|
||||
@ -314,23 +316,34 @@ void Server::handleTimeout()
|
||||
setTimeout(KEEP_ALIVE_INTERVAL);
|
||||
}
|
||||
|
||||
uint32_t Server::reserveTunnelIp()
|
||||
uint32_t Server::reserveTunnelIp(uint32_t desiredIp)
|
||||
{
|
||||
uint32_t ip = network + 2;
|
||||
if (desiredIp > network + 1 && desiredIp < network + 255 && !usedIps.count(desiredIp))
|
||||
{
|
||||
usedIps.insert(desiredIp);
|
||||
return desiredIp;
|
||||
}
|
||||
|
||||
list<uint32_t>::iterator i;
|
||||
for (i = usedIps.begin(); i != usedIps.end(); ++i)
|
||||
{
|
||||
if (*i > ip)
|
||||
break;
|
||||
ip = ip + 1;
|
||||
}
|
||||
bool ipAvailable = false;
|
||||
|
||||
if (ip - network >= 255)
|
||||
for (int i = 0; i < 255 - FIRST_ASSIGNED_IP_OFFSET; i++)
|
||||
{
|
||||
latestAssignedIpOffset++;
|
||||
if (latestAssignedIpOffset == 255)
|
||||
latestAssignedIpOffset = FIRST_ASSIGNED_IP_OFFSET;
|
||||
|
||||
if (!usedIps.count(network + latestAssignedIpOffset))
|
||||
{
|
||||
ipAvailable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ipAvailable)
|
||||
return 0;
|
||||
|
||||
usedIps.insert(i, ip);
|
||||
return ip;
|
||||
usedIps.insert(network + latestAssignedIpOffset);
|
||||
return network + latestAssignedIpOffset;
|
||||
}
|
||||
|
||||
void Server::run()
|
||||
|
8
server.h
8
server.h
@ -26,7 +26,7 @@
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
class Server : public Worker
|
||||
{
|
||||
@ -37,6 +37,7 @@ public:
|
||||
struct ClientConnectData
|
||||
{
|
||||
uint8_t maxPolls;
|
||||
uint32_t desiredIp;
|
||||
};
|
||||
|
||||
static const Worker::TunnelHeader::Magic magic;
|
||||
@ -101,7 +102,7 @@ protected:
|
||||
|
||||
void pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq);
|
||||
|
||||
uint32_t reserveTunnelIp();
|
||||
uint32_t reserveTunnelIp(uint32_t desiredIp);
|
||||
void releaseTunnelIp(uint32_t tunnelIp);
|
||||
|
||||
ClientData *getClientByTunnelIp(uint32_t ip);
|
||||
@ -110,7 +111,8 @@ protected:
|
||||
Auth auth;
|
||||
|
||||
uint32_t network;
|
||||
std::list<uint32_t> usedIps;
|
||||
std::set<uint32_t> usedIps;
|
||||
uint32_t latestAssignedIpOffset;
|
||||
|
||||
Time pollTimeout;
|
||||
|
||||
|
11
tun.cpp
11
tun.cpp
@ -89,21 +89,14 @@ void Tun::setIp(uint32_t ip, uint32_t destIp, bool includeSubnet)
|
||||
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", length);
|
||||
if (errno != EINVAL) // can be caused by invalid data packet
|
||||
throw Exception("writing to tun", true);
|
||||
}
|
||||
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", length);
|
||||
throw Exception("reading from tun", true);
|
||||
}
|
||||
syslog(LOG_ERR, "error reading from tun: %s", strerror(errno));
|
||||
return length;
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,8 @@ void Worker::run()
|
||||
if (dataLength == 0)
|
||||
throw Exception("tunnel closed");
|
||||
|
||||
handleTunData(dataLength, sourceIp, destIp);
|
||||
if (dataLength != -1)
|
||||
handleTunData(dataLength, sourceIp, destIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user