mirror of
https://github.com/norohind/hans.git
synced 2025-06-10 12:22:19 +03:00
improved ip assignment
more stable error handling
This commit is contained in:
parent
6f211f8ee9
commit
98327991f1
19
client.cpp
19
client.cpp
@ -31,11 +31,14 @@ using namespace std;
|
|||||||
|
|
||||||
const Worker::TunnelHeader::Magic Client::magic("hanc");
|
const Worker::TunnelHeader::Magic Client::magic("hanc");
|
||||||
|
|
||||||
Client::Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, int maxPolls,
|
Client::Client(int tunnelMtu, const char *deviceName, uint32_t serverIp,
|
||||||
const char *passphrase, uid_t uid, gid_t gid, bool changeEchoId, bool changeEchoSeq)
|
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)
|
: 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->maxPolls = maxPolls;
|
||||||
this->nextEchoId = Utility::rand();
|
this->nextEchoId = Utility::rand();
|
||||||
this->changeEchoId = changeEchoId;
|
this->changeEchoId = changeEchoId;
|
||||||
@ -54,6 +57,7 @@ void Client::sendConnectionRequest()
|
|||||||
{
|
{
|
||||||
Server::ClientConnectData *connectData = (Server::ClientConnectData *)echoSendPayloadBuffer();
|
Server::ClientConnectData *connectData = (Server::ClientConnectData *)echoSendPayloadBuffer();
|
||||||
connectData->maxPolls = maxPolls;
|
connectData->maxPolls = maxPolls;
|
||||||
|
connectData->desiredIp = desiredIp;
|
||||||
|
|
||||||
syslog(LOG_DEBUG, "sending connection request");
|
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:
|
case TunnelHeader::TYPE_RESET_CONNECTION:
|
||||||
syslog(LOG_DEBUG, "reset reveiced");
|
syslog(LOG_DEBUG, "reset reveiced");
|
||||||
|
|
||||||
if (privilegesDropped)
|
|
||||||
throw Exception("cannot reconnect without root privileges");
|
|
||||||
|
|
||||||
sendConnectionRequest();
|
sendConnectionRequest();
|
||||||
return true;
|
return true;
|
||||||
case TunnelHeader::TYPE_SERVER_FULL:
|
case TunnelHeader::TYPE_SERVER_FULL:
|
||||||
@ -128,7 +129,15 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
|
|||||||
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");
|
||||||
|
|
||||||
|
clientIp = ip;
|
||||||
|
desiredIp = ip;
|
||||||
tun->setIp(ip, (ip & 0xffffff00) + 1, false);
|
tun->setIp(ip, (ip & 0xffffff00) + 1, false);
|
||||||
|
}
|
||||||
state = STATE_ESTABLISHED;
|
state = STATE_ESTABLISHED;
|
||||||
|
|
||||||
dropPrivileges();
|
dropPrivileges();
|
||||||
|
7
client.h
7
client.h
@ -28,8 +28,9 @@
|
|||||||
class Client : public Worker
|
class Client : public Worker
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Client(int tunnelMtu, const char *deviceName, uint32_t serverIp, int maxPolls,
|
Client(int tunnelMtu, const char *deviceName, uint32_t serverIp,
|
||||||
const char *passphrase, uid_t uid, gid_t gid, bool changeEchoId, bool changeEchoSeq);
|
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();
|
||||||
@ -59,6 +60,8 @@ protected:
|
|||||||
Auth auth;
|
Auth auth;
|
||||||
|
|
||||||
uint32_t serverIp;
|
uint32_t serverIp;
|
||||||
|
uint32_t clientIp;
|
||||||
|
uint32_t desiredIp;
|
||||||
|
|
||||||
int maxPolls;
|
int maxPolls;
|
||||||
int pollTimeoutNr;
|
int pollTimeoutNr;
|
||||||
|
10
echo.cpp
10
echo.cpp
@ -26,6 +26,9 @@
|
|||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
typedef ip IpHeader;
|
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));
|
int result = sendto(fd, sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
|
||||||
if (result == -1)
|
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)
|
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);
|
int dataLength = recvfrom(fd, receiveBuffer, bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
|
||||||
if (dataLength == -1)
|
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))
|
if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader))
|
||||||
return -1;
|
return -1;
|
||||||
|
11
main.cpp
11
main.cpp
@ -36,7 +36,7 @@ void usage()
|
|||||||
printf(
|
printf(
|
||||||
"Hans - IP over ICMP version 0.3.1\n\n"
|
"Hans - IP over ICMP version 0.3.1\n\n"
|
||||||
"RUN AS SERVER\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"
|
"RUN AS CLIENT\n"
|
||||||
" hans -c server [-fv] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu] [-w polls]\n\n"
|
" hans -c server [-fv] [-p password] [-u unprivileged_user] [-d tun_device] [-m reference_mtu] [-w polls]\n\n"
|
||||||
"ARGUMENTS\n"
|
"ARGUMENTS\n"
|
||||||
@ -55,6 +55,7 @@ void usage()
|
|||||||
" 0 disables polling. Defaults to 10.\n"
|
" 0 disables polling. Defaults to 10.\n"
|
||||||
" -i Change the echo id for every echo request.\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 mtu = 1500;
|
||||||
int maxPolls = 10;
|
int maxPolls = 10;
|
||||||
uint32_t network = INADDR_NONE;
|
uint32_t network = INADDR_NONE;
|
||||||
|
uint32_t clientIp = INADDR_NONE;
|
||||||
bool answerPing = false;
|
bool answerPing = false;
|
||||||
uid_t uid = 0;
|
uid_t uid = 0;
|
||||||
gid_t gid = 0;
|
gid_t gid = 0;
|
||||||
@ -80,7 +82,7 @@ int main(int argc, char *argv[])
|
|||||||
openlog(argv[0], LOG_PERROR, LOG_DAEMON);
|
openlog(argv[0], LOG_PERROR, LOG_DAEMON);
|
||||||
|
|
||||||
int c;
|
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) {
|
switch(c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -124,6 +126,9 @@ int main(int argc, char *argv[])
|
|||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
clientIp = ntohl(inet_addr(optarg));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
return 1;
|
return 1;
|
||||||
@ -190,7 +195,7 @@ int main(int argc, char *argv[])
|
|||||||
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);
|
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq, clientIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foreground)
|
if (!foreground)
|
||||||
|
41
server.cpp
41
server.cpp
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#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 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->network = network & 0xffffff00;
|
||||||
this->pollTimeout = pollTimeout;
|
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);
|
||||||
|
|
||||||
@ -65,7 +68,7 @@ void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uin
|
|||||||
|
|
||||||
client.maxPolls = connectData->maxPolls;
|
client.maxPolls = connectData->maxPolls;
|
||||||
client.state = ClientData::STATE_NEW;
|
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());
|
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)
|
if (dataLength == 0)
|
||||||
{
|
{
|
||||||
syslog(LOG_WARNING, "received empty data packet");
|
syslog(LOG_WARNING, "received empty data packet");
|
||||||
throw 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +296,7 @@ void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
|
|||||||
|
|
||||||
void Server::releaseTunnelIp(uint32_t tunnelIp)
|
void Server::releaseTunnelIp(uint32_t tunnelIp)
|
||||||
{
|
{
|
||||||
usedIps.remove(tunnelIp);
|
usedIps.erase(tunnelIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::handleTimeout()
|
void Server::handleTimeout()
|
||||||
@ -314,23 +316,34 @@ void Server::handleTimeout()
|
|||||||
setTimeout(KEEP_ALIVE_INTERVAL);
|
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))
|
||||||
|
|
||||||
list<uint32_t>::iterator i;
|
|
||||||
for (i = usedIps.begin(); i != usedIps.end(); ++i)
|
|
||||||
{
|
{
|
||||||
if (*i > ip)
|
usedIps.insert(desiredIp);
|
||||||
break;
|
return desiredIp;
|
||||||
ip = ip + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ip - network >= 255)
|
bool ipAvailable = false;
|
||||||
|
|
||||||
|
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;
|
return 0;
|
||||||
|
|
||||||
usedIps.insert(i, ip);
|
usedIps.insert(network + latestAssignedIpOffset);
|
||||||
return ip;
|
return network + latestAssignedIpOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::run()
|
void Server::run()
|
||||||
|
8
server.h
8
server.h
@ -26,7 +26,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <list>
|
#include <set>
|
||||||
|
|
||||||
class Server : public Worker
|
class Server : public Worker
|
||||||
{
|
{
|
||||||
@ -37,6 +37,7 @@ public:
|
|||||||
struct ClientConnectData
|
struct ClientConnectData
|
||||||
{
|
{
|
||||||
uint8_t maxPolls;
|
uint8_t maxPolls;
|
||||||
|
uint32_t desiredIp;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Worker::TunnelHeader::Magic magic;
|
static const Worker::TunnelHeader::Magic magic;
|
||||||
@ -101,7 +102,7 @@ protected:
|
|||||||
|
|
||||||
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 reserveTunnelIp(uint32_t desiredIp);
|
||||||
void releaseTunnelIp(uint32_t tunnelIp);
|
void releaseTunnelIp(uint32_t tunnelIp);
|
||||||
|
|
||||||
ClientData *getClientByTunnelIp(uint32_t ip);
|
ClientData *getClientByTunnelIp(uint32_t ip);
|
||||||
@ -110,7 +111,8 @@ protected:
|
|||||||
Auth auth;
|
Auth auth;
|
||||||
|
|
||||||
uint32_t network;
|
uint32_t network;
|
||||||
std::list<uint32_t> usedIps;
|
std::set<uint32_t> usedIps;
|
||||||
|
uint32_t latestAssignedIpOffset;
|
||||||
|
|
||||||
Time pollTimeout;
|
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)
|
void Tun::write(const char *buffer, int length)
|
||||||
{
|
{
|
||||||
if (tun_write(fd, (char *)buffer, length) == -1)
|
if (tun_write(fd, (char *)buffer, length) == -1)
|
||||||
{
|
syslog(LOG_ERR, "error writing %d bytes to tun: %s", length, strerror(errno));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Tun::read(char *buffer)
|
int Tun::read(char *buffer)
|
||||||
{
|
{
|
||||||
int length = tun_read(fd, buffer, mtu);
|
int length = tun_read(fd, buffer, mtu);
|
||||||
if (length == -1)
|
if (length == -1)
|
||||||
{
|
syslog(LOG_ERR, "error reading from tun: %s", strerror(errno));
|
||||||
syslog(LOG_ERR, "error reading from tun", length);
|
|
||||||
throw Exception("reading from tun", true);
|
|
||||||
}
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +175,7 @@ void Worker::run()
|
|||||||
if (dataLength == 0)
|
if (dataLength == 0)
|
||||||
throw Exception("tunnel closed");
|
throw Exception("tunnel closed");
|
||||||
|
|
||||||
|
if (dataLength != -1)
|
||||||
handleTunData(dataLength, sourceIp, destIp);
|
handleTunData(dataLength, sourceIp, destIp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user