Compare commits

..

41 Commits

Author SHA1 Message Date
266a5f7d7a
Use iproute2 instead of net-tools 2022-10-15 01:49:47 +03:00
Friedrich Schöller
7659a5e173 Generate clearer log messages 2017-06-07 01:36:24 +02:00
Friedrich Schöller
41f9ed5ef4 More towards C++ 2017-06-07 01:36:18 +02:00
Friedrich Schöller
c9b07d96bc Log invalid request type 2017-05-14 00:07:21 +02:00
Friedrich Schöller
295f6b4051 Enable and fix most C++ warnings 2017-05-14 00:07:21 +02:00
Friedrich Schöller
7991b11a15 Remove unused code 2017-05-14 00:07:21 +02:00
Friedrich Schöller
6ae989fdee Print nicer usage text 2017-05-14 00:07:17 +02:00
Friedrich Schöller
4c10ac711a Free address info 2017-05-13 15:03:01 +02:00
Friedrich Schöller
0801a67257 Fix server name resolution
When resolving the name of a server, the result was always assumed to
be an IPv4 address, even if an IPv6 address was actually returned.

Use `getaddrinfo` instead of `gethostbyname` and specify that we are
only interested in IPv4 addresses.
2017-05-13 14:21:33 +02:00
Friedrich Schöller
f0eb5a46ac Fix client list
The client list was broken in a way that could lead to undefined
behavior when multiple clients connected to a server.
2017-05-13 14:21:16 +02:00
Friedrich Schöller
3cd2bb95dd Version 1.0 2016-11-18 15:53:39 +01:00
Friedrich Schöller
535ddc75c7 Fixed compile error on FreeBSD 2016-11-18 15:27:25 +01:00
Friedrich Schöller
ed3d7de6cc Remove supplementary groups when dropping privileges
Suggested by xambroz.
2016-11-18 14:38:18 +01:00
Friedrich Schöller
5e1004038f Fixed compiler warnings on Windows 2016-11-18 14:21:47 +01:00
Friedrich Schöller
032089ce7a Fixed "not supported" error on Windows 2016-01-05 16:05:10 +01:00
Friedrich Schöller
74bad3b702 Merge branch 'refs/heads/master' into cygwin 2014-02-07 04:39:32 +01:00
Friedrich Schöller
da404dac65 Version 0.4.4 2014-02-07 04:36:31 +01:00
Friedrich Schöller
e6d7f4c043 Fixed writing beyond array bounds 2014-02-07 04:35:00 +01:00
Friedrich Schöller
a4b81ef64d Removed trailing whitespace 2013-06-07 02:20:39 +02:00
Friedrich Schöller
3a39facc56 Small fixes 2013-05-22 02:55:22 +02:00
Friedrich Schöller
1be922591e Finishing up 2013-05-22 02:38:52 +02:00
Friedrich Schöller
b805963b3a Throw exception when trying to drop privileges on windows 2013-05-22 02:13:23 +02:00
Friedrich Schöller
ca42f469b4 Conditional includes and device name length 2013-05-22 02:12:26 +02:00
Friedrich Schöller
308e87270a Merge branch 'refs/heads/master' into cygwin 2013-05-22 01:16:03 +02:00
Friedrich Schöller
893ac91eaf Stop worker on signal 2013-05-22 01:15:31 +02:00
Friedrich Schöller
aee7af9cc1 Merge branch 'refs/heads/master' into cygwin 2013-05-22 00:28:00 +02:00
Friedrich Schöller
c70575ee96 Added missing include 2013-05-22 00:27:20 +02:00
Friedrich Schöller
7d6c1dc290 Fixed netsh call on windows 2013-05-14 02:47:37 +02:00
Friedrich Schöller
7fa3579c7e Fixed version string 2013-05-14 00:27:58 +02:00
Friedrich Schöller
da01402651 Fixed version string 2013-05-14 00:27:30 +02:00
Friedrich Schöller
01a65b13e3 Added cygwin support (client only) 2013-05-13 23:31:27 +02:00
Friedrich Schöller
1b2370143d Inform about server mode working on linux only 2013-05-13 23:29:38 +02:00
Friedrich Schöller
d79187028a Log opened tunnel device 2013-05-13 17:14:19 +02:00
Friedrich Schöller
0d03ebbefe Fixed error on cleanup 2013-05-13 14:06:41 +02:00
Friedrich Schöller
6f534b31e9 Fixed Makefile dependency 2013-05-13 13:58:37 +02:00
Friedrich Schöller
b58ad1bee8 Improved tun error reporting 2013-05-13 13:58:05 +02:00
Friedrich Schöller
3459887cf7 Made usage() static 2013-05-13 13:56:49 +02:00
Friedrich Schöller
736099944d Clean exit on signal 2013-05-13 13:56:27 +02:00
Friedrich Schöller
363a9d765e Updated CHANGES 2013-05-03 22:37:23 +02:00
Friedrich Schöller
31dba9e57b Removed .gitignore 2013-05-03 22:37:15 +02:00
Friedrich Schöller
65429e8a49 Fixed includes, updated copyright 2013-05-03 22:31:18 +02:00
34 changed files with 932 additions and 402 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
/hans
/build

19
CHANGES
View File

@ -1,5 +1,22 @@
Release 1.0 (November 2016)
---------------------------
* Added cygwin support
* Remove supplementary groups when dropping privileges
* Fixed compile error on FreeBSD
Release 0.4.4 (February 2014)
-----------------------------
* Fixed writing beyond array bounds
* Fixed some smaller bugs
* Clean exit on signal
* Improved error reporting
Release 0.4.3 (Mai 2013)
------------------------
* Fixed tunemu compiling issue
Release 0.4.2 (Mai 2013)
-----------------
------------------------
* Fixed compilation issue on Linux
* Changed the license of tunemu from GPL to BSD
* Minor changes

View File

@ -1,12 +1,13 @@
LDFLAGS = `sh osflags ld $(MODE)`
CFLAGS = -c -g `sh osflags c $(MODE)`
CPPFLAGS = -c -g -std=c++98 -pedantic -Wall -Wextra -Wno-sign-compare -Wno-missing-field-initializers `sh osflags c $(MODE)`
TUN_DEV_FILE = `sh osflags dev $(MODE)`
GCC = gcc
GPP = g++
.PHONY: directories
all: hans
all: directories hans
directories: build_dir
@ -15,48 +16,47 @@ build_dir:
tunemu.o: directories build/tunemu.o
hans: directories build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o
hans: build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o
$(GPP) -o hans build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o $(LDFLAGS)
build/utility.o: src/utility.cpp src/utility.h
$(GPP) -c src/utility.cpp -o $@ -o $@ $(CFLAGS)
$(GPP) -c src/utility.cpp -o $@ -o $@ $(CPPFLAGS)
build/exception.o: src/exception.cpp src/exception.h
$(GPP) -c src/exception.cpp -o $@ $(CFLAGS)
$(GPP) -c src/exception.cpp -o $@ $(CPPFLAGS)
build/echo.o: src/echo.cpp src/echo.h src/exception.h
$(GPP) -c src/echo.cpp -o $@ $(CFLAGS)
$(GPP) -c src/echo.cpp -o $@ $(CPPFLAGS)
build/tun.o: src/tun.cpp src/tun.h src/exception.h src/utility.h src/tun_dev.h
$(GPP) -c src/tun.cpp -o $@ $(CFLAGS)
$(GPP) -c src/tun.cpp -o $@ $(CPPFLAGS)
build/tun_dev.o:
$(GCC) -c $(TUN_DEV_FILE) -o build/tun_dev.o -o $@ $(CFLAGS)
build/sha1.o: src/sha1.cpp src/sha1.h
$(GPP) -c src/sha1.cpp -o $@ $(CFLAGS)
$(GPP) -c src/sha1.cpp -o $@ $(CPPFLAGS)
build/main.o: src/main.cpp src/client.h src/server.h src/exception.h src/worker.h src/auth.h src/time.h src/echo.h src/tun.h src/tun_dev.h
$(GPP) -c src/main.cpp -o $@ $(CFLAGS)
$(GPP) -c src/main.cpp -o $@ $(CPPFLAGS)
build/client.o: src/client.cpp src/client.h src/server.h src/exception.h src/config.h src/worker.h src/auth.h src/time.h src/echo.h src/tun.h src/tun_dev.h
$(GPP) -c src/client.cpp -o $@ $(CFLAGS)
$(GPP) -c src/client.cpp -o $@ $(CPPFLAGS)
build/server.o: src/server.cpp src/server.h src/client.h src/utility.h src/config.h src/worker.h src/auth.h src/time.h src/echo.h src/tun.h src/tun_dev.h
$(GPP) -c src/server.cpp -o $@ $(CFLAGS)
$(GPP) -c src/server.cpp -o $@ $(CPPFLAGS)
build/auth.o: src/auth.cpp src/auth.h src/sha1.h src/utility.h
$(GPP) -c src/auth.cpp -o $@ $(CFLAGS)
$(GPP) -c src/auth.cpp -o $@ $(CPPFLAGS)
build/worker.o: src/worker.cpp src/worker.h src/tun.h src/exception.h src/time.h src/echo.h src/tun_dev.h src/config.h
$(GPP) -c src/worker.cpp -o $@ $(CFLAGS)
$(GPP) -c src/worker.cpp -o $@ $(CPPFLAGS)
build/time.o: src/time.cpp src/time.h
$(GPP) -c src/time.cpp -o $@ $(CFLAGS)
$(GPP) -c src/time.cpp -o $@ $(CPPFLAGS)
clean:
rm -f build/tun.o build/sha1.o build/main.o build/client.o build/server.o build/auth.o build/worker.o build/time.o build/tun_dev.o build/echo.o build/exception.o build/utility.o build/tunemu.o hans
rm -df build
rm -rf build hans
build/tunemu.o: src/tunemu.h src/tunemu.c
$(GCC) -c src/tunemu.c -o build/tunemu.o

11
osflags
View File

@ -14,11 +14,12 @@ ld)
esac
;;
c)
FLAGS=-D$OS
case $OS in
LINUX)
echo $FLAGS -DHAVE_LINUX_IF_TUN_H
echo $FLAGS -DHAVE_LINUX_IF_TUN_H -DLINUX
;;
CYGWIN*)
echo $FLAGS -DWIN32
;;
*)
echo $FLAGS
@ -43,10 +44,12 @@ dev)
echo src/tun_dev_generic.c
fi
;;
CYGWIN*)
echo src/tun_dev_cygwin.c
;;
*)
echo src/tun_dev_generic.c
;;
esac
;;
esac

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "auth.h"
@ -23,10 +23,9 @@
#include <arpa/inet.h>
Auth::Auth(const char *passphrase)
{
this->passphrase = passphrase;
}
Auth::Auth(const std::string &passphrase)
: passphrase(passphrase)
{ }
Auth::Response Auth::getResponse(const Challenge &challenge) const
{
@ -34,11 +33,11 @@ Auth::Response Auth::getResponse(const Challenge &challenge) const
Response response;
hasher << passphrase.c_str();
hasher << passphrase.data();
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]);

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef AUTH_H
@ -36,7 +36,7 @@ public:
bool operator==(const Response &other) const { return memcmp(this, &other, sizeof(Response)) == 0; }
};
Auth(const char *passphrase);
Auth(const std::string &passphrase);
Challenge generateChallenge(int length) const;
Response getResponse(const Challenge &challenge) const;

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "client.h"
@ -28,14 +28,15 @@
#include <netinet/in.h>
#include <syslog.h>
using namespace std;
using std::vector;
using std::string;
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,
Client::Client(int tunnelMtu, const string *deviceName, uint32_t serverIp,
int maxPolls, const string &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->clientIp = INADDR_NONE;
@ -89,7 +90,7 @@ void Client::sendChallengeResponse(int dataLength)
setTimeout(5000);
}
bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t realIp, bool reply, uint16_t, uint16_t)
{
if (realIp != serverIp || !reply)
return false;
@ -100,7 +101,7 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
switch (header.type)
{
case TunnelHeader::TYPE_RESET_CONNECTION:
syslog(LOG_DEBUG, "reset reveiced");
syslog(LOG_DEBUG, "reset received");
sendConnectionRequest();
return true;
@ -113,7 +114,7 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
case TunnelHeader::TYPE_CHALLENGE:
if (state == STATE_CONNECTION_REQUEST_SENT)
{
syslog(LOG_DEBUG, "challenge received");
syslog(LOG_DEBUG, "authentication request received");
sendChallengeResponse(dataLength);
return true;
}
@ -137,7 +138,7 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
clientIp = ip;
desiredIp = ip;
tun->setIp(ip, (ip & 0xffffff00) + 1, false);
tun.setIp(ip, (ip & 0xffffff00) + 1);
}
state = STATE_ESTABLISHED;
@ -160,6 +161,8 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
return true;
}
break;
default:
break;
}
syslog(LOG_DEBUG, "invalid packet type: %d, state: %d", header.type, state);
@ -167,7 +170,7 @@ bool Client::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
return true;
}
void Client::sendEchoToServer(int type, int dataLength)
void Client::sendEchoToServer(Worker::TunnelHeader::Type type, int dataLength)
{
if (maxPolls == 0 && state == STATE_ESTABLISHED)
setTimeout(KEEP_ALIVE_INTERVAL);
@ -208,7 +211,7 @@ void Client::handleDataFromServer(int dataLength)
sendEchoToServer(TunnelHeader::TYPE_POLL, 0);
}
void Client::handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp)
void Client::handleTunData(int dataLength, uint32_t, uint32_t)
{
if (state != STATE_ESTABLISHED)
return;

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef CLIENT_H
@ -27,9 +27,10 @@
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,
Client(int tunnelMtu, const std::string *deviceName, uint32_t serverIp,
int maxPolls, const std::string &passphrase, uid_t uid, gid_t gid,
bool changeEchoId, bool changeEchoSeq, uint32_t desiredIp);
virtual ~Client();
@ -53,7 +54,7 @@ protected:
void startPolling();
void sendEchoToServer(int type, int dataLength);
void sendEchoToServer(Worker::TunnelHeader::Type type, int dataLength);
void sendChallengeResponse(int dataLength);
void sendConnectionRequest();

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#define MAX_BUFFERED_PACKETS 20
@ -24,5 +24,5 @@
#define CHALLENGE_SIZE 20
//#define DEBUG_ONLY(a) a
// #define DEBUG_ONLY(a) a
#define DEBUG_ONLY(a)

View File

@ -1,26 +1,27 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "echo.h"
#include "exception.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
@ -41,16 +42,13 @@ Echo::Echo(int maxPayloadSize)
throw Exception("creating icmp socket", true);
bufferSize = maxPayloadSize + headerSize();
sendBuffer = new char[bufferSize];
receiveBuffer = new char[bufferSize];
sendBuffer.resize(bufferSize);
receiveBuffer.resize(bufferSize);
}
Echo::~Echo()
{
close(fd);
delete[] sendBuffer;
delete[] receiveBuffer;
}
int Echo::headerSize()
@ -67,15 +65,15 @@ void Echo::send(int payloadLength, uint32_t realIp, bool reply, uint16_t id, uin
if (payloadLength + sizeof(IpHeader) + sizeof(EchoHeader) > bufferSize)
throw Exception("packet too big");
EchoHeader *header = (EchoHeader *)(sendBuffer + sizeof(IpHeader));
EchoHeader *header = (EchoHeader *)(sendBuffer.data() + 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));
header->chksum = icmpChecksum(sendBuffer.data() + sizeof(IpHeader), payloadLength + sizeof(EchoHeader));
int result = sendto(fd, sendBuffer + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
int result = sendto(fd, sendBuffer.data() + sizeof(IpHeader), payloadLength + sizeof(EchoHeader), 0, (struct sockaddr *)&target, sizeof(struct sockaddr_in));
if (result == -1)
syslog(LOG_ERR, "error sending icmp packet: %s", strerror(errno));
}
@ -85,7 +83,7 @@ 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);
int dataLength = recvfrom(fd, receiveBuffer, bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
int dataLength = recvfrom(fd, receiveBuffer.data(), bufferSize, 0, (struct sockaddr *)&source, (socklen_t *)&source_addr_len);
if (dataLength == -1)
{
syslog(LOG_ERR, "error receiving icmp packet: %s", strerror(errno));
@ -95,7 +93,7 @@ int Echo::receive(uint32_t &realIp, bool &reply, uint16_t &id, uint16_t &seq)
if (dataLength < sizeof(IpHeader) + sizeof(EchoHeader))
return -1;
EchoHeader *header = (EchoHeader *)(receiveBuffer + sizeof(IpHeader));
EchoHeader *header = (EchoHeader *)(receiveBuffer.data() + sizeof(IpHeader));
if ((header->type != 0 && header->type != 8) || header->code != 0)
return -1;
@ -111,13 +109,23 @@ 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;
}
char *Echo::sendPayloadBuffer()
{
return sendBuffer.data() + headerSize();
}
char *Echo::receivePayloadBuffer()
{
return receiveBuffer.data() + headerSize();
}

View File

@ -1,26 +1,27 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef ECHO_H
#define ECHO_H
#include <string>
#include <vector>
#include <stdint.h>
class Echo
@ -34,8 +35,8 @@ public:
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();
char *receivePayloadBuffer();
static int headerSize();
protected:
@ -52,7 +53,8 @@ protected:
int fd;
int bufferSize;
char *sendBuffer, *receiveBuffer;
std::vector<char> sendBuffer;
std::vector<char> receiveBuffer;
};
#endif

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "exception.h"
@ -23,17 +23,17 @@
#include <stdio.h>
#include <string.h>
using namespace std;
using std::string;
Exception::Exception(const char *msg)
Exception::Exception(const string &msg)
{
this->msg = msg;
}
Exception::Exception(const char *msg, bool appendSystemError)
Exception::Exception(const string &msg, bool appendSystemError)
{
if (appendSystemError)
this->msg = string(msg) + ": " + strerror(errno);
this->msg = msg + ": " + strerror(errno);
else
this->msg = msg;
}

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include <string>
@ -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 std::string &msg);
Exception(const std::string &msg, bool appendSystemError);
const std::string &errorMessage() const { return msg; }
protected:
std::string msg;
};

View File

@ -1,27 +1,27 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "client.h"
#include "server.h"
#include "exception.h"
#include <stdio.h>
#include <iostream>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
@ -34,41 +34,70 @@
#include <syslog.h>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>
#include <memory>
void usage()
#ifndef AI_V4MAPPED // Not supported on OpenBSD 6.0
#define AI_V4MAPPED 0
#endif
using std::string;
static Worker *worker = NULL;
static void sig_term_handler(int)
{
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"
syslog(LOG_INFO, "SIGTERM received");
if (worker)
worker->stop();
}
static void sig_int_handler(int)
{
syslog(LOG_INFO, "SIGINT received");
if (worker)
worker->stop();
}
static void usage()
{
std::cerr <<
"Hans - IP over ICMP version 1.0\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"
" hans -c server [-fv] [-p passphrase] [-u user] [-d tun_device]\n"
" [-m reference_mtu] [-w polls]\n\n"
"RUN AS SERVER (linux only)\n"
" hans -s network [-fvr] [-p passphrase] [-u user] [-d tun_device]\n"
" [-m reference_mtu] [-a ip]\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"
" -c server Run as client. Connect to given server address.\n"
" -s network Run as server. Use given network address on virtual interfaces.\n"
" -p passphrase Set passphrase.\n"
" -u username Change user under which the program runs.\n"
" -a ip Request assignment of given tunnel ip address from the server.\n"
" -r Respond to ordinary pings in server mode.\n"
" -d device Use given tun device.\n"
" -m mtu Set maximum echo packet size. This should correspond to the MTU\n"
" of the network between client and server, which is usually 1500\n"
" over Ethernet. Has to be the same on client and server. Defaults\n"
" to 1500.\n"
" -w polls Number of echo requests the client sends in advance for the\n"
" server to reply to. 0 disables polling, which is the best choice\n"
" if the network allows unlimited echo replies. Defaults to 10.\n"
" -i Change echo id on every echo request. May help with buggy\n"
" routers. May impact performance with others.\n"
" -q Change echo sequence number on every echo request. May help with\n"
" buggy routers. May impact performance with others.\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"
);
" -v Print debug information.\n";
}
int main(int argc, char *argv[])
{
const char *serverName;
const char *userName = NULL;
const char *password = "";
const char *device = NULL;
string serverName;
string userName;
string passphrase;
string device;
bool isServer = false;
bool isClient = false;
bool foreground = false;
@ -82,7 +111,7 @@ int main(int argc, char *argv[])
bool changeEchoId = false;
bool changeEchoSeq = false;
bool verbose = false;
openlog(argv[0], LOG_PERROR, LOG_DAEMON);
int c;
@ -99,8 +128,8 @@ int main(int argc, char *argv[])
device = optarg;
break;
case 'p':
password = strdup(optarg);
memset(optarg, 0, strlen(optarg));
passphrase = optarg;
memset(optarg, 0, strlen(optarg));
break;
case 'c':
isClient = true;
@ -110,7 +139,7 @@ int main(int argc, char *argv[])
isServer = true;
network = ntohl(inet_addr(optarg));
if (network == INADDR_NONE)
printf("invalid network\n");
std::cerr << "invalid network\n";
break;
case 'm':
mtu = atoi(optarg);
@ -143,8 +172,9 @@ int main(int argc, char *argv[])
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");
// RFC 791: Every internet module must be able to forward a datagram of
// 68 octets without further fragmentation.
std::cerr << "mtu too small\n";
return 1;
}
@ -157,9 +187,13 @@ int main(int argc, char *argv[])
return 1;
}
if (userName != NULL)
if (!userName.empty())
{
passwd *pw = getpwnam(userName);
#ifdef WIN32
syslog(LOG_ERR, "dropping privileges is not supported on Windows");
return 1;
#endif
passwd *pw = getpwnam(userName.data());
if (pw != NULL)
{
@ -176,30 +210,39 @@ int main(int argc, char *argv[])
if (!verbose)
setlogmask(LOG_UPTO(LOG_INFO));
signal(SIGTERM, sig_term_handler);
signal(SIGINT, sig_int_handler);
try
{
Worker *worker;
if (isServer)
{
worker = new Server(mtu, device, password, network, answerPing, uid, gid, 5000);
worker = new Server(mtu, device.empty() ? NULL : &device, passphrase,
network, answerPing, uid, gid, 5000);
}
else
{
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;
}
struct addrinfo hints = {0};
struct addrinfo *res = NULL;
serverIp = *(uint32_t *)he->h_addr;
hints.ai_family = AF_INET;
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
int err = getaddrinfo(serverName.data(), NULL, &hints, &res);
if (err)
{
syslog(LOG_ERR, "getaddrinfo: %s", gai_strerror(err));
return 1;
}
worker = new Client(mtu, device, ntohl(serverIp), maxPolls, password, uid, gid, changeEchoId, changeEchoSeq, clientIp);
sockaddr_in *sockaddr = reinterpret_cast<sockaddr_in *>(res->ai_addr);
uint32_t serverIp = sockaddr->sin_addr.s_addr;
worker = new Client(mtu, device.empty() ? NULL : &device,
ntohl(serverIp), maxPolls, passphrase, uid, gid,
changeEchoId, changeEchoSeq, clientIp);
freeaddrinfo(res);
}
if (!foreground)
@ -212,7 +255,8 @@ int main(int argc, char *argv[])
}
catch (Exception e)
{
syslog(LOG_ERR, "%s", e.errorMessage());
syslog(LOG_ERR, "%s", e.errorMessage().data());
delete worker;
return 1;
}

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "server.h"
@ -25,21 +25,25 @@
#include <string.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <iostream>
using namespace std;
using std::string;
using std::cout;
using std::endl;
#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)
Server::Server(int tunnelMtu, const string *deviceName, const string &passphrase,
uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout)
: Worker(tunnelMtu, deviceName, answerEcho, uid, gid), auth(passphrase)
{
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);
dropPrivileges();
}
@ -59,7 +63,8 @@ void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uin
if (header.type != TunnelHeader::TYPE_CONNECTION_REQUEST || dataLength != sizeof(ClientConnectData))
{
syslog(LOG_DEBUG, "invalid request %s", Utility::formatIp(realIp).c_str());
syslog(LOG_DEBUG, "invalid request (type %d) from %s", header.type,
Utility::formatIp(realIp).c_str());
sendReset(&client);
return;
}
@ -70,7 +75,9 @@ void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uin
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 with tunnel address %s\n",
Utility::formatIp(client.realIp).data(),
Utility::formatIp(client.tunnelIp).data());
if (client.tunnelIp != 0)
{
@ -78,9 +85,9 @@ void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uin
sendChallenge(&client);
// add client to list
clientList.push_back(client);
clientRealIpMap[realIp] = clientList.size() - 1;
clientTunnelIpMap[client.tunnelIp] = clientList.size() - 1;
clientList.push_front(client);
clientRealIpMap[realIp] = clientList.begin();
clientTunnelIpMap[client.tunnelIp] = clientList.begin();
}
else
{
@ -91,7 +98,8 @@ void Server::handleUnknownClient(const TunnelHeader &header, int dataLength, uin
void Server::sendChallenge(ClientData *client)
{
syslog(LOG_DEBUG, "sending challenge to: %s\n", Utility::formatIp(client->realIp).c_str());
syslog(LOG_DEBUG, "sending authentication request to %s\n",
Utility::formatIp(client->realIp).data());
memcpy(echoSendPayloadBuffer(), &client->challenge[0], client->challenge.size());
sendEchoToClient(client, TunnelHeader::TYPE_CHALLENGE, client->challenge.size());
@ -101,16 +109,18 @@ void Server::sendChallenge(ClientData *client)
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 with tunnel ip %s\n",
Utility::formatIp(client->realIp).data(),
Utility::formatIp(client->tunnelIp).data());
releaseTunnelIp(client->tunnelIp);
int nr = clientRealIpMap[client->realIp];
ClientList::iterator it = clientRealIpMap[client->realIp];
clientRealIpMap.erase(client->realIp);
clientTunnelIpMap.erase(client->tunnelIp);
clientList.erase(clientList.begin() + nr);
clientList.erase(it);
}
void Server::checkChallenge(ClientData *client, int length)
@ -119,7 +129,8 @@ void Server::checkChallenge(ClientData *client, int length)
if (length != sizeof(Auth::Response) || memcmp(&rightResponse, echoReceivePayloadBuffer(), length) != 0)
{
syslog(LOG_DEBUG, "wrong challenge response\n");
syslog(LOG_DEBUG, "wrong challenge response from %s\n",
Utility::formatIp(client->realIp).data());
sendEchoToClient(client, TunnelHeader::TYPE_CHALLENGE_ERROR, 0);
@ -134,12 +145,14 @@ void Server::checkChallenge(ClientData *client, int length)
client->state = ClientData::STATE_ESTABLISHED;
syslog(LOG_INFO, "connection established: %s", Utility::formatIp(client->realIp).c_str());
syslog(LOG_INFO, "connection established to %s",
Utility::formatIp(client->realIp).data());
}
void Server::sendReset(ClientData *client)
{
syslog(LOG_DEBUG, "sending reset: %s", Utility::formatIp(client->realIp).c_str());
syslog(LOG_DEBUG, "sending reset to %s",
Utility::formatIp(client->realIp).data());
sendEchoToClient(client, TunnelHeader::TYPE_RESET_CONNECTION, 0);
}
@ -172,7 +185,7 @@ bool Server::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
while (client->pollIds.size() > 1)
client->pollIds.pop();
syslog(LOG_DEBUG, "reconnecting %s", Utility::formatIp(realIp).c_str());
syslog(LOG_DEBUG, "reconnecting %s", Utility::formatIp(realIp).data());
sendReset(client);
removeClient(client);
return true;
@ -198,32 +211,35 @@ bool Server::handleEchoData(const TunnelHeader &header, int dataLength, uint32_t
break;
case TunnelHeader::TYPE_POLL:
return true;
default:
break;
}
syslog(LOG_DEBUG, "invalid packet from: %s, type: %d, state: %d", Utility::formatIp(realIp).c_str(), header.type, client->state);
syslog(LOG_DEBUG, "invalid packet from: %s, type: %d, state: %d",
Utility::formatIp(realIp).data(), header.type, client->state);
return true;
}
Server::ClientData *Server::getClientByTunnelIp(uint32_t ip)
{
ClientIpMap::iterator clientMapIterator = clientTunnelIpMap.find(ip);
if (clientMapIterator == clientTunnelIpMap.end())
ClientIpMap::iterator it = clientTunnelIpMap.find(ip);
if (it == clientTunnelIpMap.end())
return NULL;
return &clientList[clientMapIterator->second];
return &*it->second;
}
Server::ClientData *Server::getClientByRealIp(uint32_t ip)
{
ClientIpMap::iterator clientMapIterator = clientRealIpMap.find(ip);
if (clientMapIterator == clientRealIpMap.end())
ClientIpMap::iterator it = clientRealIpMap.find(ip);
if (it == clientRealIpMap.end())
return NULL;
return &clientList[clientMapIterator->second];
return &*it->second;
}
void Server::handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp)
void Server::handleTunData(int dataLength, uint32_t, uint32_t destIp)
{
if (destIp == network + 255) // ignore broadcasts
return;
@ -232,7 +248,8 @@ void Server::handleTunData(int dataLength, uint32_t sourceIp, uint32_t destIp)
if (client == NULL)
{
syslog(LOG_DEBUG, "unknown client: %s\n", Utility::formatIp(destIp).c_str());
syslog(LOG_DEBUG, "data received for unknown client %s\n",
Utility::formatIp(destIp).data());
return;
}
@ -246,7 +263,7 @@ void Server::pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq)
client->pollIds.push(ClientData::EchoId(echoId, echoSeq));
if (client->pollIds.size() > maxSavedPolls)
client->pollIds.pop();
DEBUG_ONLY(printf("poll -> %d\n", client->pollIds.size()));
DEBUG_ONLY(cout << "poll -> " << client->pollIds.size() << endl);
if (client->pendingPackets.size() > 0)
{
@ -254,14 +271,14 @@ void Server::pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq)
memcpy(echoSendPayloadBuffer(), &packet.data[0], packet.data.size());
client->pendingPackets.pop();
DEBUG_ONLY(printf("pending packet: %d bytes\n", packet.data.size()));
DEBUG_ONLY(cout << "pending packet: " << packet.data.size() << " bytes\n");
sendEchoToClient(client, packet.type, packet.data.size());
}
client->lastActivity = now;
}
void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
void Server::sendEchoToClient(ClientData *client, TunnelHeader::Type type, int dataLength)
{
if (client->maxPolls == 0)
{
@ -274,7 +291,7 @@ void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
ClientData::EchoId echoId = client->pollIds.front();
client->pollIds.pop();
DEBUG_ONLY(printf("sending -> %d\n", client->pollIds.size()));
DEBUG_ONLY(cout << "sending -> " << client->pollIds.size() << endl);
sendEcho(magic, type, dataLength, client->realIp, true, echoId.id, echoId.seq);
return;
}
@ -282,10 +299,11 @@ void Server::sendEchoToClient(ClientData *client, int type, int dataLength)
if (client->pendingPackets.size() == MAX_BUFFERED_PACKETS)
{
client->pendingPackets.pop();
syslog(LOG_WARNING, "packet dropped to %s", Utility::formatIp(client->tunnelIp).c_str());
syslog(LOG_WARNING, "packet to %s dropped",
Utility::formatIp(client->tunnelIp).data());
}
DEBUG_ONLY(printf("packet queued: %d bytes\n", dataLength));
DEBUG_ONLY(cout << "packet queued: " << dataLength << " bytes\n");
client->pendingPackets.push(Packet());
Packet &packet = client->pendingPackets.back();
@ -301,15 +319,16 @@ void Server::releaseTunnelIp(uint32_t tunnelIp)
void Server::handleTimeout()
{
for (int i = 0; i < clientList.size(); i++)
ClientList::iterator it = clientList.begin();
while (it != clientList.end())
{
ClientData *client = &clientList[i];
ClientData &client = *it++;
if (client->lastActivity + KEEP_ALIVE_INTERVAL * 2 < now)
if (client.lastActivity + KEEP_ALIVE_INTERVAL * 2 < now)
{
syslog(LOG_DEBUG, "client timeout: %s\n", Utility::formatIp(client->realIp).c_str());
removeClient(client);
i--;
syslog(LOG_DEBUG, "client %s timed out\n",
Utility::formatIp(client.realIp).data());
removeClient(&client);
}
}

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef SERVER_H
@ -26,28 +26,29 @@
#include <map>
#include <queue>
#include <vector>
#include <list>
#include <set>
#include <string>
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);
Server(int tunnelMtu, const std::string *deviceName, const std::string &passphrase,
uint32_t network, bool answerEcho, uid_t uid, gid_t gid, int pollTimeout);
virtual ~Server();
// change some time:
// struct __attribute__ ((__packed__)) ClientConnectData
struct ClientConnectData
{
uint8_t maxPolls;
uint32_t desiredIp;
};
static const Worker::TunnelHeader::Magic magic;
static const TunnelHeader::Magic magic;
protected:
struct Packet
{
int type;
TunnelHeader::Type type;
std::vector<char> data;
};
@ -82,8 +83,8 @@ protected:
Auth::Challenge challenge;
};
typedef std::vector<ClientData> ClientList;
typedef std::map<uint32_t, int> ClientIpMap;
typedef std::list<ClientData> ClientList;
typedef std::map<uint32_t, ClientList::iterator> 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);
@ -100,7 +101,7 @@ protected:
void checkChallenge(ClientData *client, int dataLength);
void sendReset(ClientData *client);
void sendEchoToClient(ClientData *client, int type, int dataLength);
void sendEchoToClient(ClientData *client, TunnelHeader::Type type, int dataLength);
void pollReceived(ClientData *client, uint16_t echoId, uint16_t echoSeq);

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "time.h"
@ -32,13 +32,13 @@ 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;
}
@ -47,13 +47,13 @@ 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;
}

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef TIME_H

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "tun.h"
@ -22,82 +22,114 @@
#include "utility.h"
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sstream>
#ifdef WIN32
#include <w32api/windows.h>
#endif
typedef ip IpHeader;
using namespace std;
using std::string;
Tun::Tun(const char *device, int mtu)
#ifdef WIN32
static void winsystem(char *cmd)
{
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
if (CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
WaitForSingleObject(processInfo.hProcess, INFINITE);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
}
#endif
#define ip_path "/sbin/ip "
Tun::Tun(const string *device, int 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)
this->device = *device;
this->device.resize(VTUN_DEV_LEN);
fd = tun_open(&this->device[0]);
this->device.resize(strlen(this->device.data()));
fd = tun_open(this->device);
if (fd == -1)
throw Exception("could not create tunnel device");
throw Exception(string("could not create tunnel device: ") + tun_last_error());
char cmdline[512];
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s mtu %u", this->device, mtu);
if (system(cmdline) != 0)
syslog(LOG_INFO, "opened tunnel device: %s", this->device.data());
std::stringstream cmdline;
#ifdef WIN32
cmdline << "netsh interface ipv4 set subinterface \"" << this->device
<< "\" mtu=" << mtu;
winsystem(cmdline.str().data());
#else
// ip link set dev <device> mtu <mtu>
cmdline << ip_path << "link set dev " << this->device << " mtu " << mtu;
// cmdline << "/sbin/ifconfig " << this->device << " mtu " << mtu;
if (system(cmdline.str().data()) != 0)
syslog(LOG_ERR, "could not set tun device mtu");
#endif
}
Tun::~Tun()
{
tun_close(fd, device);
tun_close(fd, &device[0]);
}
void Tun::setIp(uint32_t ip, uint32_t destIp, bool includeSubnet)
void Tun::setIp(uint32_t ip, uint32_t destIp)
{
char cmdline[512];
std::stringstream cmdline;
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());
#else
snprintf(cmdline, sizeof(cmdline), "/sbin/ifconfig %s %s %s netmask 255.255.255.255", device, ips.c_str(), destIps.c_str());
#endif
#ifdef WIN32
cmdline << "netsh interface ip set address name=\"" << device << "\" "
<< "static " << ips << " 255.255.255.0";
winsystem(cmdline.str().data());
if (system(cmdline) != 0)
if (!tun_set_ip(fd, ip, ip & 0xffffff00, 0xffffff00))
syslog(LOG_ERR, "could not set tun device driver ip address: %s", tun_last_error());
#elif LINUX
// ip addr add <ip>/24 dev <device>
cmdline << ip_path << "addr add " << ips << "/24 dev " << device;
// cmdline << "/sbin/ifconfig " << device << " " << ips << " netmask 255.255.255.0";
if (system(cmdline.str().data()) != 0)
syslog(LOG_ERR, "could not set tun device ip address");
#else
cmdline << "/sbin/ifconfig " << device << " " << ips << " " << destIps
<< " netmask 255.255.255.255";
if (system(cmdline.str().data()) != 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");
}
#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));
syslog(LOG_ERR, "error writing %d bytes to tun: %s", length, tun_last_error());
}
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));
syslog(LOG_ERR, "error reading from tun: %s", tun_last_error());
return length;
}

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef TUN_H
@ -28,7 +28,7 @@
class Tun
{
public:
Tun(const char *device, int mtu);
Tun(const std::string *device, int mtu);
~Tun();
int getFd() { return fd; }
@ -38,9 +38,9 @@ public:
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);
protected:
char device[VTUN_DEV_LEN];
std::string device;
int mtu;
int fd;

View File

@ -1,27 +1,50 @@
/*
VTun - Virtual Tunnel over TCP/IP network.
Copyright (C) 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
VTun has been derived from VPPP package by Maxim Krasnyansky.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
/*
* Hans - IP over ICMP
* Copyright (C) 2013 Friedrich Schöller <hans@schoeller.se>
* 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifdef WIN32
#include <stdint.h>
#include <stdbool.h>
#define VTUN_DEV_LEN 100
#else
#define VTUN_DEV_LEN 20
extern "C"
{
#endif
#ifdef __cplusplus
extern "C" {
#endif
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);
const char *tun_last_error();
#ifdef WIN32
bool tun_set_ip(int fd, uint32_t local, uint32_t network, uint32_t netmask);
#endif
#ifdef __cplusplus
}
#endif

318
src/tun_dev_cygwin.c Normal file
View File

@ -0,0 +1,318 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2013 Friedrich Schöller <hans@schoeller.se>
* 2002-2005 Ivo Timmermans,
* 2002-2011 Guus Sliepen <guus@tinc-vpn.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "tun_dev.h"
#include <unistd.h>
#include <stdbool.h>
#include <syslog.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdio.h>
#include <w32api/windows.h>
#include <w32api/winioctl.h>
#define TAP_WIN_CONTROL_CODE(request,method) CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
#define TAP_WIN_IOCTL_GET_MAC TAP_WIN_CONTROL_CODE (1, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_VERSION TAP_WIN_CONTROL_CODE (2, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_MTU TAP_WIN_CONTROL_CODE (3, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_INFO TAP_WIN_CONTROL_CODE (4, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT TAP_WIN_CONTROL_CODE (5, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_SET_MEDIA_STATUS TAP_WIN_CONTROL_CODE (6, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_DHCP_MASQ TAP_WIN_CONTROL_CODE (7, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_GET_LOG_LINE TAP_WIN_CONTROL_CODE (8, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT TAP_WIN_CONTROL_CODE (9, METHOD_BUFFERED)
#define TAP_WIN_IOCTL_CONFIG_TUN TAP_WIN_CONTROL_CODE (10, METHOD_BUFFERED)
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
#define SYSDEVICEDIR "\\Device\\"
#define USERDEVICEDIR "\\DosDevices\\Global\\"
#define TAP_WIN_SUFFIX ".tap"
struct adapter_info
{
int reader_read_fd, reader_write_fd;
HANDLE reader_thread;
HANDLE adapter_handle;
};
#define ERROR_BUFFER_SIZE 1024
char error_buffer[ERROR_BUFFER_SIZE];
static void error(char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(error_buffer, ERROR_BUFFER_SIZE, format, vl);
va_end(vl);
}
static void noerror(void)
{
*error_buffer = 0;
}
static const char *winerror(int err)
{
static char buf[1024], *ptr;
ptr = buf + sprintf(buf, "(%d) ", err);
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), ptr, sizeof(buf) - (ptr - buf), NULL)) {
strcpy(ptr, "(unable to format errormessage)");
};
if((ptr = strchr(buf, '\r')))
*ptr = '\0';
return buf;
}
static struct adapter_info *get_adapter_info_from_fd(int fd)
{
static struct adapter_info single_adapter_info = {
.reader_read_fd = -1,
.reader_write_fd = -1,
.reader_thread = INVALID_HANDLE_VALUE,
.adapter_handle = INVALID_HANDLE_VALUE
};
return &single_adapter_info;
}
static HANDLE open_tap_adapter(char *name)
{
HKEY connections_key, adapter_key;
int adapter_index, error_code;
char regpath[1024];
char adapter_id[VTUN_DEV_LEN];
char adapter_path[1024];
char adapter_name[1024];
HANDLE adapter_handle = INVALID_HANDLE_VALUE;
DWORD len;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &connections_key) != ERROR_SUCCESS)
{
error("opening registry: %s", winerror(GetLastError()));
return INVALID_HANDLE_VALUE;
}
for (adapter_index = 0; ; adapter_index++)
{
len = sizeof(adapter_id);
if (RegEnumKeyEx(connections_key, adapter_index, adapter_id, &len, 0, 0, 0, NULL) != ERROR_SUCCESS)
break;
snprintf(regpath, sizeof(regpath), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, adapter_id);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &adapter_key) != ERROR_SUCCESS)
continue;
len = sizeof(adapter_name);
if (RegQueryValueEx(adapter_key, "Name", 0, 0, adapter_name, &len) != ERROR_SUCCESS)
{
RegCloseKey(adapter_key);
continue;
}
RegCloseKey(adapter_key);
if (name && name[0] && strcmp(name, adapter_name) && strcmp(name, adapter_id))
continue;
snprintf(adapter_path, sizeof(adapter_path), USERMODEDEVICEDIR "%s" TAP_WIN_SUFFIX, adapter_id);
adapter_handle = CreateFile(adapter_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if (adapter_handle != INVALID_HANDLE_VALUE)
break;
}
RegCloseKey(connections_key);
if (adapter_handle == INVALID_HANDLE_VALUE)
{
error("could not open tap adapter");
return INVALID_HANDLE_VALUE;
}
strncpy(name, adapter_name, VTUN_DEV_LEN);
noerror();
return adapter_handle;
}
static __stdcall DWORD reader_thread(LPVOID ptr)
{
struct adapter_info *adapter_info = ptr;
char buf[0xffff]; // maximum IPv4 packet size
OVERLAPPED overlapped;
DWORD len;
int wait_result;
memset(&overlapped, 0, sizeof(overlapped));
overlapped.hEvent = CreateEvent(NULL, true, false, NULL);
while (true)
{
if (!ReadFile(adapter_info->adapter_handle, buf, sizeof(buf), &len, &overlapped))
{
if (GetLastError() != ERROR_IO_PENDING)
{
syslog(LOG_ERR, "error reading from tap adapter: %s", winerror(GetLastError()));
return 1;
}
wait_result = WaitForSingleObjectEx(overlapped.hEvent, INFINITE, false);
if (wait_result != WAIT_OBJECT_0)
{
syslog(LOG_ERR, "error waiting for tap adapter: %s", winerror(GetLastError()));
return 1;
}
if (!GetOverlappedResult(adapter_info->adapter_handle, &overlapped, &len, true))
{
syslog(LOG_ERR, "error getting tap adapter reading result: %s", winerror(GetLastError()));
return 1;
}
}
write(adapter_info->reader_write_fd, buf, len);
}
}
int tun_open(char *dev)
{
struct adapter_info *adapter_info;
int socket_pair[2];
if (socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, socket_pair))
{
error("creating socket pair: %s", strerror(errno));
return -1;
}
adapter_info = get_adapter_info_from_fd(socket_pair[0]);
adapter_info->reader_read_fd = socket_pair[0];
adapter_info->reader_write_fd = socket_pair[1];
adapter_info->adapter_handle = open_tap_adapter(dev);
if (adapter_info->adapter_handle == INVALID_HANDLE_VALUE)
{
tun_close(adapter_info->reader_read_fd, NULL);
return -1;
}
adapter_info->reader_thread = CreateThread(NULL, 0, reader_thread, adapter_info, 0, NULL);
if (adapter_info->reader_thread == INVALID_HANDLE_VALUE)
{
error("reader thread creation: %s", winerror(GetLastError()));
tun_close(adapter_info->reader_read_fd, NULL);
return -1;
}
return adapter_info->reader_read_fd;
}
int tun_close(int fd, char *dev)
{
struct adapter_info *adapter_info = get_adapter_info_from_fd(fd);
if (adapter_info->reader_thread != INVALID_HANDLE_VALUE)
{
TerminateThread(adapter_info->reader_thread, 0);
adapter_info->reader_thread = INVALID_HANDLE_VALUE;
}
close(adapter_info->reader_read_fd);
adapter_info->reader_read_fd = -1;
close(adapter_info->reader_write_fd);
adapter_info->reader_write_fd = -1;
if (adapter_info->adapter_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(adapter_info->adapter_handle);
adapter_info->adapter_handle = INVALID_HANDLE_VALUE;
}
return 0;
}
int tun_write(int fd, char *buf, int len)
{
struct adapter_info *adapter_info = get_adapter_info_from_fd(fd);
OVERLAPPED overlapped;
DWORD written;
memset(&overlapped, 0, sizeof(overlapped));
if (!WriteFile(adapter_info->adapter_handle, buf, len, &written, &overlapped))
{
error("tap write: %s", winerror(GetLastError()));
return -1;
}
return written;
}
int tun_read(int fd, char *buf, int len)
{
len = read(fd, buf, len);
if (len == -1)
error("reader read: %s", strerror(errno));
return len;
}
const char *tun_last_error()
{
return error_buffer;
}
bool tun_set_ip(int fd, uint32_t local, uint32_t network, uint32_t netmask)
{
struct adapter_info *adapter_info = get_adapter_info_from_fd(fd);
uint32_t addresses[3];
DWORD status;
DWORD len;
addresses[0] = htonl(local);
addresses[1] = htonl(network);
addresses[2] = htonl(netmask);
if (!DeviceIoControl(adapter_info->adapter_handle, TAP_WIN_IOCTL_CONFIG_TUN,
&addresses, sizeof(addresses), &addresses, sizeof(addresses), &len, NULL))
{
error("configuring tap addresses: %s", winerror(GetLastError()));
return false;
}
status = true;
if (!DeviceIoControl(adapter_info->adapter_handle, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
&status, sizeof(status), &status, sizeof(status), &len, NULL))
{
error("enabling tap device: %s", winerror(GetLastError()));
return false;
}
noerror();
return true;
}

View File

@ -1,19 +1,20 @@
/*
VTun - Virtual Tunnel over TCP/IP network.
Copyright (C) 1998-2000 Maxim Krasnyansky <max_mk@yahoo.com>
VTun has been derived from VPPP package by Maxim Krasnyansky.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "tunemu.h"
@ -22,10 +23,7 @@
int tun_open(char *dev)
{
int fd = tunemu_open(dev);
if (fd < 0)
syslog(LOG_ERR, tunemu_error);
return fd;
return tunemu_open(dev);
}
int tun_close(int fd, char *dev)
@ -42,3 +40,8 @@ int tun_read(int fd, char *buf, int len)
{
return tunemu_read(fd, buf, len);
}
const char *tun_last_error()
{
return tunemu_error;
}

View File

@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if_tun.h>
@ -81,3 +82,8 @@ int tun_read(int fd, char *buf, int len)
{
return read(fd, buf, len);
}
const char *tun_last_error()
{
return strerror(errno);
}

View File

@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
/* #include "vtun.h"
#include "lib.h" */
@ -72,3 +73,8 @@ int tun_read(int fd, char *buf, int len)
{
return read(fd, buf, len);
}
const char *tun_last_error()
{
return strerror(errno);
}

View File

@ -130,3 +130,8 @@ int tap_write(int fd, char *buf, int len) { return write(fd, buf, len); }
int tun_read(int fd, char *buf, int len) { return read(fd, buf, len); }
int tap_read(int fd, char *buf, int len) { return read(fd, buf, len); }
const char *tun_last_error()
{
return strerror(errno);
}

View File

@ -28,6 +28,7 @@
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
@ -98,3 +99,8 @@ int tun_read(int fd, char *buf, int len)
else
return rlen;
}
const char *tun_last_error()
{
return strerror(errno);
}

View File

@ -175,3 +175,8 @@ int tun_read(int fd, char *buf, int len)
sbuf.buf = buf;
return getmsg(fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
}
const char *tun_last_error()
{
return strerror(errno);
}

View File

@ -1,7 +1,7 @@
/*
* tunemu - Tun device emulation for Darwin
*
* Copyright (c) 2009-2010 Friedrich Schöller <hans@schoeller.se>
* Copyright (c) 2009-2013 Friedrich Schöller <hans@schoeller.se>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -28,20 +28,18 @@
#include "tunemu.h"
#include <sys/types.h>
#include <sys/io.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <memory.h>
#include <util.h>
#include <pcap.h>
#include <stdarg.h>
#include <errno.h>
#include <stdint.h>
#include <stdint.h>
#include <ctype.h>
#include <fcntl.h>
#include <string.h>

View File

@ -1,7 +1,7 @@
/*
* tunemu - Tun device emulation for Darwin
*
* Copyright (c) 2009-2010 Friedrich Schöller <hans@schoeller.se>
* Copyright (c) 2009-2013 Friedrich Schöller <hans@schoeller.se>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "utility.h"
@ -22,14 +22,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sstream>
using namespace std;
string Utility::formatIp(uint32_t ip)
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;
std::stringstream s;
s << ((ip >> 24) & 0xff) << '.'
<< ((ip >> 16) & 0xff) << '.'
<< ((ip >> 8) & 0xff) << '.'
<< ((ip >> 0) & 0xff);
return s.str();
}
int Utility::rand()

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef UTILITY_H

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#include "worker.h"
@ -27,8 +27,11 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/select.h>
#include <grp.h>
#include <iostream>
using namespace std;
using std::cout;
using std::endl;
Worker::TunnelHeader::Magic::Magic(const char *magic)
{
@ -46,54 +49,37 @@ bool Worker::TunnelHeader::Magic::operator!=(const Magic &other) const
return memcmp(data, other.data, sizeof(data)) != 0;
}
Worker::Worker(int tunnelMtu, const char *deviceName, bool answerEcho, uid_t uid, gid_t gid)
Worker::Worker(int tunnelMtu, const std::string *deviceName, bool answerEcho,
uid_t uid, gid_t gid)
: echo(tunnelMtu + sizeof(TunnelHeader)), tun(deviceName, tunnelMtu)
{
this->tunnelMtu = tunnelMtu;
this->answerEcho = answerEcho;
this->uid = uid;
this->gid = gid;
this->privilegesDropped = false;
echo = NULL;
tun = NULL;
try
{
echo = new Echo(tunnelMtu + sizeof(TunnelHeader));
tun = new Tun(deviceName, tunnelMtu);
}
catch (...)
{
delete echo;
delete tun;
throw;
}
}
Worker::~Worker()
{
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)
void Worker::sendEcho(const TunnelHeader::Magic &magic, TunnelHeader::Type type,
int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq)
{
if (length > payloadBufferSize())
throw Exception("packet too big");
TunnelHeader *header = (TunnelHeader *)echo->sendPayloadBuffer();
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(
cout << "sending: type " << type << ", length " << length
<< ", id " << id << ", seq " << seq << endl);
echo->send(length + sizeof(TunnelHeader), realIp, reply, id, seq);
echo.send(length + sizeof(TunnelHeader), realIp, reply, id, seq);
}
void Worker::sendToTun(int length)
{
tun->write(echoReceivePayloadBuffer(), length);
tun.write(echoReceivePayloadBuffer(), length);
}
void Worker::setTimeout(Time delta)
@ -106,7 +92,7 @@ void Worker::run()
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)
{
@ -114,8 +100,8 @@ void Worker::run()
Time timeout;
FD_ZERO(&fs);
FD_SET(tun->getFd(), &fs);
FD_SET(echo->getFd(), &fs);
FD_SET(tun.getFd(), &fs);
FD_SET(echo.getFd(), &fs);
if (nextTimeout != Time::ZERO)
{
@ -125,9 +111,15 @@ void Worker::run()
}
// wait for data or timeout
int result = select(maxFd + 1 , &fs, NULL, NULL, nextTimeout != Time::ZERO ? &timeout.getTimeval() : NULL);
timeval *timeval = nextTimeout != Time::ZERO ? &timeout.getTimeval() : NULL;
int result = select(maxFd + 1 , &fs, NULL, NULL, timeval);
if (result == -1)
throw Exception("select", true);
{
if (alive)
throw Exception("select", true);
else
return;
}
now = Time::now();
// timeout
@ -139,40 +131,43 @@ void Worker::run()
}
// icmp data
if (FD_ISSET(echo->getFd(), &fs))
if (FD_ISSET(echo.getFd(), &fs))
{
bool reply;
uint16_t id, seq;
uint32_t ip;
int dataLength = echo->receive(ip, reply, id, seq);
int dataLength = echo.receive(ip, reply, id, seq);
if (dataLength != -1)
{
bool valid = dataLength >= sizeof(TunnelHeader);
if (valid)
{
TunnelHeader *header = (TunnelHeader *)echo->receivePayloadBuffer();
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(
cout << "received: type " << header->type
<< ", length " << dataLength - sizeof(TunnelHeader)
<< ", id " << id << ", seq " << seq << endl);
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);
memcpy(echo.sendPayloadBuffer(), echo.receivePayloadBuffer(), dataLength);
echo.send(dataLength, ip, true, id, seq);
}
}
}
// data from tun
if (FD_ISSET(tun->getFd(), &fs))
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");
@ -183,13 +178,24 @@ void Worker::run()
}
}
void Worker::stop()
{
alive = false;
}
void Worker::dropPrivileges()
{
if (uid <= 0 || privilegesDropped)
return;
#ifdef WIN32
throw Exception("dropping privileges not supported");
#else
syslog(LOG_INFO, "dropping privileges");
if (setgroups(0, NULL) == -1)
throw Exception("setgroups", true);
if (setgid(gid) == -1)
throw Exception("setgid", true);
@ -197,4 +203,24 @@ void Worker::dropPrivileges()
throw Exception("setuid", true);
privilegesDropped = true;
#endif
}
bool Worker::handleEchoData(const TunnelHeader &, int, uint32_t, bool, uint16_t, uint16_t)
{
return true;
}
void Worker::handleTunData(int, uint32_t, uint32_t) { }
void Worker::handleTimeout() { }
char *Worker::echoSendPayloadBuffer()
{
return echo.sendPayloadBuffer() + sizeof(TunnelHeader);
}
char *Worker::echoReceivePayloadBuffer()
{
return echo.receivePayloadBuffer() + sizeof(TunnelHeader);
}

View File

@ -1,20 +1,20 @@
/*
* Hans - IP over ICMP
* Copyright (C) 2009 Friedrich Schöller <hans@schoeller.se>
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef WORKER_H
@ -30,10 +30,12 @@
class Worker
{
public:
Worker(int tunnelMtu, const char *deviceName, bool answerEcho, uid_t uid, gid_t gid);
virtual ~Worker();
Worker(int tunnelMtu, const std::string *deviceName, bool answerEcho,
uid_t uid, gid_t gid);
virtual ~Worker() { }
virtual void run();
virtual void stop();
static int headerSize() { return sizeof(TunnelHeader); }
@ -51,41 +53,44 @@ protected:
char data[4];
};
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
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
};
Magic magic;
uint8_t type;
}; // 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);
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 sendEcho(const TunnelHeader::Magic &magic, TunnelHeader::Type type,
int length, uint32_t realIp, bool reply, uint16_t id, uint16_t seq);
void sendToTun(int length); // from echoReceivePayloadBuffer
void setTimeout(Time delta);
char *echoSendPayloadBuffer() { return echo->sendPayloadBuffer() + sizeof(TunnelHeader); }
char *echoReceivePayloadBuffer() { return echo->receivePayloadBuffer() + sizeof(TunnelHeader); }
char *echoSendPayloadBuffer();
char *echoReceivePayloadBuffer();
int payloadBufferSize() { return tunnelMtu; }
void dropPrivileges();
Echo *echo;
Tun *tun;
Echo echo;
Tun tun;
bool alive;
bool answerEcho;
int tunnelMtu;