diff options
-rw-r--r-- | src/anytun.cpp | 539 | ||||
-rw-r--r-- | src/bsd/tunDevice.cpp | 255 | ||||
-rw-r--r-- | src/bsd/tunDevice.h | 64 | ||||
-rwxr-xr-x | src/configure | 6 | ||||
-rw-r--r-- | src/linux/tunDevice.cpp | 4 |
5 files changed, 612 insertions, 256 deletions
diff --git a/src/anytun.cpp b/src/anytun.cpp index 7b03785..e3b3ce3 100644 --- a/src/anytun.cpp +++ b/src/anytun.cpp @@ -116,80 +116,88 @@ bool checkPacketSeqNr(EncryptedPacket& pack,ConnectionParam& conn) void* sender(void* p) { - ThreadParam* param = reinterpret_cast<ThreadParam*>(p); - - std::auto_ptr<Cipher> c(CipherFactory::create(gOpt.getCipher())); - std::auto_ptr<AuthAlgo> a(AuthAlgoFactory::create(gOpt.getAuthAlgo()) ); - - PlainPacket plain_packet(MAX_PACKET_LENGTH); - EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH); - - Buffer session_key(u_int32_t(SESSION_KEYLEN_ENCR)); // TODO: hardcoded size - Buffer session_salt(u_int32_t(SESSION_KEYLEN_SALT)); // TODO: hardcoded size - Buffer session_auth_key(u_int32_t(SESSION_KEYLEN_AUTH)); // TODO: hardcoded size + try + { + ThreadParam* param = reinterpret_cast<ThreadParam*>(p); - //TODO replace mux - u_int16_t mux = gOpt.getMux(); - while(1) + std::auto_ptr<Cipher> c(CipherFactory::create(gOpt.getCipher())); + std::auto_ptr<AuthAlgo> a(AuthAlgoFactory::create(gOpt.getAuthAlgo()) ); + + PlainPacket plain_packet(MAX_PACKET_LENGTH); + EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH); + + Buffer session_key(u_int32_t(SESSION_KEYLEN_ENCR)); // TODO: hardcoded size + Buffer session_salt(u_int32_t(SESSION_KEYLEN_SALT)); // TODO: hardcoded size + Buffer session_auth_key(u_int32_t(SESSION_KEYLEN_AUTH)); // TODO: hardcoded size + + //TODO replace mux + u_int16_t mux = gOpt.getMux(); + while(1) + { + plain_packet.setLength(MAX_PACKET_LENGTH); + encrypted_packet.withAuthTag(false); + encrypted_packet.setLength(MAX_PACKET_LENGTH); + + // read packet from device + u_int32_t len = param->dev.read(plain_packet.getPayload(), plain_packet.getPayloadLength()); + plain_packet.setPayloadLength(len); + // set payload type + if(param->dev.getType() == TYPE_TUN) + plain_packet.setPayloadType(PAYLOAD_TYPE_TUN); + else if(param->dev.getType() == TYPE_TAP) + plain_packet.setPayloadType(PAYLOAD_TYPE_TAP); + else + plain_packet.setPayloadType(0); + + if(param->cl.empty()) + continue; + //std::cout << "got Packet for plain "<<plain_packet.getDstAddr().toString(); + mux = gRoutingTable.getRoute(plain_packet.getDstAddr()); + //std::cout << " -> "<<mux << std::endl; + ConnectionMap::iterator cit = param->cl.getConnection(mux); + if(cit==param->cl.getEnd()) + continue; + ConnectionParam & conn = cit->second; + + if(conn.remote_host_==""||!conn.remote_port_) + continue; + // generate packet-key TODO: do this only when needed + conn.kd_.generate(LABEL_SATP_ENCRYPTION, conn.seq_nr_, session_key); + conn.kd_.generate(LABEL_SATP_SALT, conn.seq_nr_, session_salt); + + c->setKey(session_key); + c->setSalt(session_salt); + + // encrypt packet + c->encrypt(plain_packet, encrypted_packet, conn.seq_nr_, gOpt.getSenderId(), mux); + + encrypted_packet.setHeader(conn.seq_nr_, gOpt.getSenderId(), mux); + conn.seq_nr_++; + + // add authentication tag + if(a->getMaxLength()) { + encrypted_packet.addAuthTag(); + conn.kd_.generate(LABEL_SATP_MSG_AUTH, encrypted_packet.getSeqNr(), session_auth_key); + a->setKey(session_auth_key); + a->generate(encrypted_packet); + } + try + { + param->src.send(encrypted_packet.getBuf(), encrypted_packet.getLength(), conn.remote_host_, conn.remote_port_); + } + catch (std::exception e) + { + // ignoring icmp port unreachable :) and other socket errors :( + } + } + } + catch(std::exception e) { - plain_packet.setLength(MAX_PACKET_LENGTH); - encrypted_packet.withAuthTag(false); - encrypted_packet.setLength(MAX_PACKET_LENGTH); - - // read packet from device - u_int32_t len = param->dev.read(plain_packet.getPayload(), plain_packet.getPayloadLength()); - plain_packet.setPayloadLength(len); - // set payload type - if(param->dev.getType() == TYPE_TUN) - plain_packet.setPayloadType(PAYLOAD_TYPE_TUN); - else if(param->dev.getType() == TYPE_TAP) - plain_packet.setPayloadType(PAYLOAD_TYPE_TAP); - else - plain_packet.setPayloadType(0); - - if(param->cl.empty()) - continue; - //std::cout << "got Packet for plain "<<plain_packet.getDstAddr().toString(); - mux = gRoutingTable.getRoute(plain_packet.getDstAddr()); - //std::cout << " -> "<<mux << std::endl; - ConnectionMap::iterator cit = param->cl.getConnection(mux); - if(cit==param->cl.getEnd()) - continue; - ConnectionParam & conn = cit->second; - - if(conn.remote_host_==""||!conn.remote_port_) - continue; - // generate packet-key TODO: do this only when needed - conn.kd_.generate(LABEL_SATP_ENCRYPTION, conn.seq_nr_, session_key); - conn.kd_.generate(LABEL_SATP_SALT, conn.seq_nr_, session_salt); - - c->setKey(session_key); - c->setSalt(session_salt); - - // encrypt packet - c->encrypt(plain_packet, encrypted_packet, conn.seq_nr_, gOpt.getSenderId(), mux); - - encrypted_packet.setHeader(conn.seq_nr_, gOpt.getSenderId(), mux); - conn.seq_nr_++; - - // add authentication tag - if(a->getMaxLength()) { - encrypted_packet.addAuthTag(); - conn.kd_.generate(LABEL_SATP_MSG_AUTH, encrypted_packet.getSeqNr(), session_auth_key); - a->setKey(session_auth_key); - a->generate(encrypted_packet); - } - try - { - param->src.send(encrypted_packet.getBuf(), encrypted_packet.getLength(), conn.remote_host_, conn.remote_port_); - } - catch (std::exception e) - { - } + cLog.msg(Log::PRIO_ERR) << "sender thread died due to an uncaught exception: " << e.what(); } pthread_exit(NULL); } - + #ifndef ANYTUN_NOSYNC void* syncConnector(void* p ) { @@ -228,88 +236,96 @@ void* syncListener(void* p ) void* receiver(void* p) { - ThreadParam* param = reinterpret_cast<ThreadParam*>(p); - - std::auto_ptr<Cipher> c( CipherFactory::create(gOpt.getCipher()) ); - std::auto_ptr<AuthAlgo> a( AuthAlgoFactory::create(gOpt.getAuthAlgo()) ); - - EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH); - PlainPacket plain_packet(MAX_PACKET_LENGTH); - - Buffer session_key(u_int32_t(SESSION_KEYLEN_ENCR)); // TODO: hardcoded size - Buffer session_salt(u_int32_t(SESSION_KEYLEN_SALT)); // TODO: hardcoded size - Buffer session_auth_key(u_int32_t(SESSION_KEYLEN_AUTH)); // TODO: hardcoded size - - while(1) + try { - string remote_host; - u_int16_t remote_port; - - plain_packet.setLength(MAX_PACKET_LENGTH); - encrypted_packet.withAuthTag(false); - encrypted_packet.setLength(MAX_PACKET_LENGTH); - - // read packet from socket - u_int32_t len = param->src.recv(encrypted_packet.getBuf(), encrypted_packet.getLength(), remote_host, remote_port); - encrypted_packet.setLength(len); + ThreadParam* param = reinterpret_cast<ThreadParam*>(p); - mux_t mux = encrypted_packet.getMux(); - // autodetect peer - if(gOpt.getRemoteAddr() == "" && param->cl.empty()) - { - cLog.msg(Log::PRIO_NOTICE) << "autodetected remote host " << remote_host << ":" << remote_port; - createConnection(remote_host, remote_port, param->cl, gOpt.getSeqWindowSize(),param->queue,mux); - } - - ConnectionMap::iterator cit = param->cl.getConnection(mux); - if (cit == param->cl.getEnd()) - continue; - ConnectionParam & conn = cit->second; - - // check whether auth tag is ok or not - if(a->getMaxLength()) { - encrypted_packet.withAuthTag(true); - conn.kd_.generate(LABEL_SATP_MSG_AUTH, encrypted_packet.getSeqNr(), session_auth_key); - a->setKey(session_auth_key); - if(!a->checkTag(encrypted_packet)) { - cLog.msg(Log::PRIO_NOTICE) << "wrong Authentication Tag!" << std::endl; - continue; - } - encrypted_packet.removeAuthTag(); - } - - //Allow dynamic IP changes - //TODO: add command line option to turn this off - if (remote_host != conn.remote_host_ || remote_port != conn.remote_port_) - { - cLog.msg(Log::PRIO_NOTICE) << "connection "<< mux << " autodetected remote host ip changed " << remote_host << ":" << remote_port; - conn.remote_host_=remote_host; - conn.remote_port_=remote_port; - SyncCommand sc (param->cl,mux); - param->queue.push(sc); - } - - // Replay Protection - if (!checkPacketSeqNr(encrypted_packet, conn)) - continue; + std::auto_ptr<Cipher> c( CipherFactory::create(gOpt.getCipher()) ); + std::auto_ptr<AuthAlgo> a( AuthAlgoFactory::create(gOpt.getAuthAlgo()) ); + + EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH); + PlainPacket plain_packet(MAX_PACKET_LENGTH); - // generate packet-key - conn.kd_.generate(LABEL_SATP_ENCRYPTION, encrypted_packet.getSeqNr(), session_key); - conn.kd_.generate(LABEL_SATP_SALT, encrypted_packet.getSeqNr(), session_salt); - c->setKey(session_key); - c->setSalt(session_salt); - - // decrypt packet - c->decrypt(encrypted_packet, plain_packet); + Buffer session_key(u_int32_t(SESSION_KEYLEN_ENCR)); // TODO: hardcoded size + Buffer session_salt(u_int32_t(SESSION_KEYLEN_SALT)); // TODO: hardcoded size + Buffer session_auth_key(u_int32_t(SESSION_KEYLEN_AUTH)); // TODO: hardcoded size - // check payload_type - if((param->dev.getType() == TYPE_TUN && plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN4 && - plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN6) || - (param->dev.getType() == TYPE_TAP && plain_packet.getPayloadType() != PAYLOAD_TYPE_TAP)) - continue; - - // write it on the device - param->dev.write(plain_packet.getPayload(), plain_packet.getLength()); + while(1) + { + string remote_host; + u_int16_t remote_port; + + plain_packet.setLength(MAX_PACKET_LENGTH); + encrypted_packet.withAuthTag(false); + encrypted_packet.setLength(MAX_PACKET_LENGTH); + + // read packet from socket + u_int32_t len = param->src.recv(encrypted_packet.getBuf(), encrypted_packet.getLength(), remote_host, remote_port); + encrypted_packet.setLength(len); + + mux_t mux = encrypted_packet.getMux(); + // autodetect peer + if(gOpt.getRemoteAddr() == "" && param->cl.empty()) + { + cLog.msg(Log::PRIO_NOTICE) << "autodetected remote host " << remote_host << ":" << remote_port; + createConnection(remote_host, remote_port, param->cl, gOpt.getSeqWindowSize(),param->queue,mux); + } + + ConnectionMap::iterator cit = param->cl.getConnection(mux); + if (cit == param->cl.getEnd()) + continue; + ConnectionParam & conn = cit->second; + + // check whether auth tag is ok or not + if(a->getMaxLength()) { + encrypted_packet.withAuthTag(true); + conn.kd_.generate(LABEL_SATP_MSG_AUTH, encrypted_packet.getSeqNr(), session_auth_key); + a->setKey(session_auth_key); + if(!a->checkTag(encrypted_packet)) { + cLog.msg(Log::PRIO_NOTICE) << "wrong Authentication Tag!" << std::endl; + continue; + } + encrypted_packet.removeAuthTag(); + } + + //Allow dynamic IP changes + //TODO: add command line option to turn this off + if (remote_host != conn.remote_host_ || remote_port != conn.remote_port_) + { + cLog.msg(Log::PRIO_NOTICE) << "connection "<< mux << " autodetected remote host ip changed " + << remote_host << ":" << remote_port; + conn.remote_host_=remote_host; + conn.remote_port_=remote_port; + SyncCommand sc (param->cl,mux); + param->queue.push(sc); + } + + // Replay Protection + if (!checkPacketSeqNr(encrypted_packet, conn)) + continue; + + // generate packet-key + conn.kd_.generate(LABEL_SATP_ENCRYPTION, encrypted_packet.getSeqNr(), session_key); + conn.kd_.generate(LABEL_SATP_SALT, encrypted_packet.getSeqNr(), session_salt); + c->setKey(session_key); + c->setSalt(session_salt); + + // decrypt packet + c->decrypt(encrypted_packet, plain_packet); + + // check payload_type + if((param->dev.getType() == TYPE_TUN && plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN4 && + plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN6) || + (param->dev.getType() == TYPE_TAP && plain_packet.getPayloadType() != PAYLOAD_TYPE_TAP)) + continue; + + // write it on the device + param->dev.write(plain_packet.getPayload(), plain_packet.getLength()); + } + } + catch(std::exception e) + { + cLog.msg(Log::PRIO_ERR) << "receiver thread died due to an uncaught exception: " << e.what(); } pthread_exit(NULL); } @@ -427,122 +443,135 @@ int execScript(string const& script, string const& ifname) int main(int argc, char* argv[]) { -// std::cout << "anytun - secure anycast tunneling protocol" << std::endl; - if(!gOpt.parse(argc, argv)) { - gOpt.printUsage(); - exit(-1); - } - - cLog.msg(Log::PRIO_NOTICE) << "anytun started..."; + bool daemonized=false; + try + { - std::ofstream pidFile; - if(gOpt.getPidFile() != "") { - pidFile.open(gOpt.getPidFile().c_str()); - if(!pidFile.is_open()) { - std::cout << "can't open pid file" << std::endl; +// std::cout << "anytun - secure anycast tunneling protocol" << std::endl; + if(!gOpt.parse(argc, argv)) { + gOpt.printUsage(); + exit(-1); } - } - - TunDevice dev(gOpt.getDevName() =="" ? NULL : gOpt.getDevName().c_str(), - gOpt.getDevType() =="" ? NULL : gOpt.getDevType().c_str(), - gOpt.getIfconfigParamLocal() =="" ? NULL : gOpt.getIfconfigParamLocal().c_str(), - gOpt.getIfconfigParamRemoteNetmask() =="" ? NULL : gOpt.getIfconfigParamRemoteNetmask().c_str()); - cLog.msg(Log::PRIO_NOTICE) << "dev created (opened)"; - cLog.msg(Log::PRIO_NOTICE) << "dev opened - actual name is '" << dev.getActualName() << "'"; - cLog.msg(Log::PRIO_NOTICE) << "dev type is '" << dev.getTypeString() << "'"; - if(gOpt.getPostUpScript() != "") { - int postup_ret = execScript(gOpt.getPostUpScript(), dev.getActualName()); - cLog.msg(Log::PRIO_NOTICE) << "post up script '" << gOpt.getPostUpScript() << "' returned " << postup_ret; - } - - -// Buffer buff(u_int32_t(1600)); -// int len; -// while(1) -// { -// len = dev.read(buff.getBuf(), buff.getLength()); -// std::cout << "read " << len << " bytes form interface " << dev.getActualName() << std::endl; -// dev.write(buff.getBuf(), len); -// } - -// exit(0); - - - - - if(gOpt.getChroot()) - chrootAndDrop(gOpt.getChrootDir(), gOpt.getUsername()); - if(gOpt.getDaemonize()) - daemonize(); - - if(pidFile.is_open()) { - pid_t pid = getpid(); - pidFile << pid; - pidFile.close(); - } - - SignalController sig; - sig.init(); - - PacketSource* src; - if(gOpt.getLocalAddr() == "") - src = new UDPPacketSource(gOpt.getLocalPort()); - else - src = new UDPPacketSource(gOpt.getLocalAddr(), gOpt.getLocalPort()); - - ConnectionList cl; - ConnectToList connect_to = gOpt.getConnectTo(); - SyncQueue queue; - - if(gOpt.getRemoteAddr() != "") - createConnection(gOpt.getRemoteAddr(),gOpt.getRemotePort(),cl,gOpt.getSeqWindowSize(), queue, gOpt.getMux()); - - ThreadParam p(dev, *src, cl, queue,*(new OptionConnectTo())); - // this must be called before any other libgcrypt call - if(!initLibGCrypt()) - return -1; - - pthread_t senderThread; - pthread_create(&senderThread, NULL, sender, &p); - pthread_t receiverThread; - pthread_create(&receiverThread, NULL, receiver, &p); + cLog.msg(Log::PRIO_NOTICE) << "anytun started..."; + + std::ofstream pidFile; + if(gOpt.getPidFile() != "") { + pidFile.open(gOpt.getPidFile().c_str()); + if(!pidFile.is_open()) { + std::cout << "can't open pid file" << std::endl; + } + } + + TunDevice dev(gOpt.getDevName() =="" ? NULL : gOpt.getDevName().c_str(), + gOpt.getDevType() =="" ? NULL : gOpt.getDevType().c_str(), + gOpt.getIfconfigParamLocal() =="" ? NULL : gOpt.getIfconfigParamLocal().c_str(), + gOpt.getIfconfigParamRemoteNetmask() =="" ? NULL : gOpt.getIfconfigParamRemoteNetmask().c_str()); + cLog.msg(Log::PRIO_NOTICE) << "dev created (opened)"; + cLog.msg(Log::PRIO_NOTICE) << "dev opened - actual name is '" << dev.getActualName() << "'"; + cLog.msg(Log::PRIO_NOTICE) << "dev type is '" << dev.getTypeString() << "'"; + if(gOpt.getPostUpScript() != "") { + int postup_ret = execScript(gOpt.getPostUpScript(), dev.getActualName()); + cLog.msg(Log::PRIO_NOTICE) << "post up script '" << gOpt.getPostUpScript() << "' returned " << postup_ret; + } + + +// Buffer buff(u_int32_t(1600)); +// int len; +// while(1) +// { +// len = dev.read(buff.getBuf(), buff.getLength()); +// std::cout << "read " << len << " bytes form interface " << dev.getActualName() << std::endl; +// dev.write(buff.getBuf(), len); +// } + +// return 0; + + + + if(gOpt.getChroot()) + chrootAndDrop(gOpt.getChrootDir(), gOpt.getUsername()); + if(gOpt.getDaemonize()) + daemonize(); + daemonized = true; + + if(pidFile.is_open()) { + pid_t pid = getpid(); + pidFile << pid; + pidFile.close(); + } + + SignalController sig; + sig.init(); + + PacketSource* src; + if(gOpt.getLocalAddr() == "") + src = new UDPPacketSource(gOpt.getLocalPort()); + else + src = new UDPPacketSource(gOpt.getLocalAddr(), gOpt.getLocalPort()); + + ConnectionList cl; + ConnectToList connect_to = gOpt.getConnectTo(); + SyncQueue queue; + + if(gOpt.getRemoteAddr() != "") + createConnection(gOpt.getRemoteAddr(),gOpt.getRemotePort(),cl,gOpt.getSeqWindowSize(), queue, gOpt.getMux()); + + ThreadParam p(dev, *src, cl, queue,*(new OptionConnectTo())); + + // this must be called before any other libgcrypt call + if(!initLibGCrypt()) + return -1; + + pthread_t senderThread; + pthread_create(&senderThread, NULL, sender, &p); + pthread_t receiverThread; + pthread_create(&receiverThread, NULL, receiver, &p); #ifndef ANYTUN_NOSYNC - pthread_t syncListenerThread; - if ( gOpt.getLocalSyncPort()) - pthread_create(&syncListenerThread, NULL, syncListener, &p); - - std::list<pthread_t> connectThreads; - for(ConnectToList::iterator it = connect_to.begin() ;it != connect_to.end(); ++it) { - connectThreads.push_back(pthread_t()); - ThreadParam * point = new ThreadParam(dev, *src, cl, queue,*it); - pthread_create(& connectThreads.back(), NULL, syncConnector, point); - } + pthread_t syncListenerThread; + if ( gOpt.getLocalSyncPort()) + pthread_create(&syncListenerThread, NULL, syncListener, &p); + + std::list<pthread_t> connectThreads; + for(ConnectToList::iterator it = connect_to.begin() ;it != connect_to.end(); ++it) { + connectThreads.push_back(pthread_t()); + ThreadParam * point = new ThreadParam(dev, *src, cl, queue,*it); + pthread_create(& connectThreads.back(), NULL, syncConnector, point); + } #endif - - int ret = sig.run(); - - pthread_cancel(senderThread); - pthread_cancel(receiverThread); + + int ret = sig.run(); + + pthread_cancel(senderThread); + pthread_cancel(receiverThread); #ifndef ANYTUN_NOSYNC - if ( gOpt.getLocalSyncPort()) - pthread_cancel(syncListenerThread); - for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it) - pthread_cancel(*it); + if ( gOpt.getLocalSyncPort()) + pthread_cancel(syncListenerThread); + for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it) + pthread_cancel(*it); #endif - - pthread_join(senderThread, NULL); - pthread_join(receiverThread, NULL); + + pthread_join(senderThread, NULL); + pthread_join(receiverThread, NULL); #ifndef ANYTUN_NOSYNC - if ( gOpt.getLocalSyncPort()) - pthread_join(syncListenerThread, NULL); - - for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it) - pthread_join(*it, NULL); + if ( gOpt.getLocalSyncPort()) + pthread_join(syncListenerThread, NULL); + + for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it) + pthread_join(*it, NULL); #endif - delete src; - delete &p.connto; + delete src; + delete &p.connto; - return ret; + return ret; + } + catch(std::exception e) + { + if(daemonized) + cLog.msg(Log::PRIO_ERR) << "uncaught exception, exiting: " << e.what(); + else + std::cout << "uncaught exception, exiting: " << e.what() << std::endl; + } } - + + diff --git a/src/bsd/tunDevice.cpp b/src/bsd/tunDevice.cpp new file mode 100644 index 0000000..47558de --- /dev/null +++ b/src/bsd/tunDevice.cpp @@ -0,0 +1,255 @@ +/* + * anytun + * + * The secure anycast tunneling protocol (satp) defines a protocol used + * for communication between any combination of unicast and anycast + * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel + * mode and allows tunneling of every ETHER TYPE protocol (e.g. + * ethernet, ip, arp ...). satp directly includes cryptography and + * message authentication based on the methodes used by SRTP. It is + * intended to deliver a generic, scaleable and secure solution for + * tunneling and relaying of packets of any protocol. + * + * + * Copyright (C) 2007 anytun.org <satp@wirdorange.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_tun.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> + +#include <sstream> + +#include "tunDevice.h" +#include "threadUtils.hpp" +#define DEVICE_FILE_MAX 255 + +#include <iostream> + +TunDevice::TunDevice(const char* dev_name, const char* dev_type, const char* ifcfg_lp, const char* ifcfg_rnmp) : conf_(dev_name, dev_type, ifcfg_lp, ifcfg_rnmp) +{ + std::string device_file = "/dev/"; + bool dynamic = true; + if(dev_name) { + device_file.append(dev_name); + dynamic = false; + } + else if(conf_.type_ == TYPE_TUN) { + device_file.append("tun"); + actual_name_ = "tun"; + } + else if(conf_.type_ == TYPE_TAP) { + device_file.append("tap"); + actual_name_ = "tap"; + } + else + throw std::runtime_error("unable to recognize type of device (tun or tap)"); + + u_int32_t dev_id=0; + if(dynamic) { + for(; dev_id <= DEVICE_FILE_MAX; ++dev_id) { + std::ostringstream ds; + ds << device_file; + ds << dev_id; + fd_ = ::open(ds.str().c_str(), O_RDWR); + if(fd_ >= 0) + break; + } + } + else + fd_ = ::open(device_file.c_str(), O_RDWR); + + if(fd_ < 0) { + std::string msg; + if(dynamic) + msg = "can't open device file dynamically: no unused node left"; + else { + msg = "can't open device file ("; + msg.append(device_file); + msg.append("): "); + msg.append(strerror(errno)); + } + throw std::runtime_error(msg); + } + + if(dynamic) { + std::stringstream s; + s << actual_name_; + s << dev_id; + actual_name_ = s.str(); + } + else + actual_name_ = dev_name; + + init_post(); + + if(ifcfg_lp && ifcfg_rnmp) + do_ifconfig(); +} + +TunDevice::~TunDevice() +{ + if(fd_ > 0) + ::close(fd_); +} + +#if defined(__GNUC__) && defined(__OpenBSD__) + +void TunDevice::init_post() +{ + with_type_ = true; + if(conf_.type_ == TYPE_TAP) + with_type_ = false; + + struct tuninfo ti; + + if (ioctl(fd_, TUNGIFINFO, &ti) < 0) + throw std::runtime_error("can't enable multicast for interface"); + + ti.flags |= IFF_MULTICAST; + + if (ioctl(fd_, TUNSIFINFO, &ti) < 0) + throw std::runtime_error("can't enable multicast for interface"); +} + +#elif defined(__GNUC__) && defined(__FreeBSD__) + +void TunDevice::init_post() +{ + with_type_ = true; + if(conf_.type_ == TYPE_TAP) + with_type_ = false; + + int arg = 0; + ioctl(fd_, TUNSLMODE, &arg); + arg = 1; + ioctl(fd_, TUNSIFHEAD, &arg); +} + +#elif defined(__GNUC__) && defined(__NetBSD__) + +void TunDevice::init_post() +{ + with_type_ = false; + + int arg = IFF_POINTOPOINT|IFF_MULTICAST; + ioctl(fd_, TUNSIFMODE, &arg); + arg = 0; + ioctl(fd_, TUNSLMODE, &arg); +} + +#else + #error Target not supported +#endif + + +short TunDevice::read(u_int8_t* buf, u_int32_t len) +{ + if(fd_ < 0) + return -1; + + if(with_type_) { + struct iovec iov[2]; + u_int32_t type; + + iov[0].iov_base = &type; + iov[0].iov_len = sizeof(type); + iov[1].iov_base = buf; + iov[1].iov_len = len; + return(::readv(fd_, iov, 2) - sizeof(type)); + } + else + return(::read(fd_, buf, len)); +} + +int TunDevice::write(u_int8_t* buf, u_int32_t len) +{ + if(fd_ < 0) + return -1; + + if(with_type_) { + struct iovec iov[2]; + u_int32_t type; + struct ip *hdr = reinterpret_cast<struct ip*>(buf); + + type = 0; + if(hdr->ip_v == 4) + type = htonl(AF_INET); + else + type = htonl(AF_INET6); + + iov[0].iov_base = &type; + iov[0].iov_len = sizeof(type); + iov[1].iov_base = buf; + iov[1].iov_len = len; + return(::writev(fd_, iov, 2) - sizeof(type)); + } + else + return(::write(fd_, buf, len)); +} + +const char* TunDevice::getActualName() +{ + return actual_name_.c_str(); +} + +device_type_t TunDevice::getType() +{ + return conf_.type_; +} + +const char* TunDevice::getTypeString() +{ + if(fd_ < 0) + return NULL; + + switch(conf_.type_) + { + case TYPE_UNDEF: return "undef"; break; + case TYPE_TUN: return "tun"; break; + case TYPE_TAP: return "tap"; break; + } + return NULL; +} + +void TunDevice::do_ifconfig() +{ +// std::string command("/sbin/ifconfig "); +// command.append(actual_name_); +// command.append(" "); +// command.append(conf_.local_.toString()); +// command.append(" "); + +// if(conf_.type_ == TYPE_TUN) +// command.append("pointopoint "); +// else +// command.append("netmask "); + +// command.append(conf_.remote_netmask_.toString()); +// command.append(" mtu 1400"); + +// system(command.c_str()); +} diff --git a/src/bsd/tunDevice.h b/src/bsd/tunDevice.h new file mode 100644 index 0000000..16408a2 --- /dev/null +++ b/src/bsd/tunDevice.h @@ -0,0 +1,64 @@ +/* + * anytun + * + * The secure anycast tunneling protocol (satp) defines a protocol used + * for communication between any combination of unicast and anycast + * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel + * mode and allows tunneling of every ETHER TYPE protocol (e.g. + * ethernet, ip, arp ...). satp directly includes cryptography and + * message authentication based on the methodes used by SRTP. It is + * intended to deliver a generic, scaleable and secure solution for + * tunneling and relaying of packets of any protocol. + * + * + * Copyright (C) 2007 anytun.org <satp@wirdorange.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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 (see the file COPYING included with this + * distribution); if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _TUNDEVICE_H_ +#define _TUNDEVICE_H_ + +#include "buffer.h" +#include "deviceConfig.hpp" +#include "threadUtils.hpp" + +class TunDevice +{ +public: + TunDevice(const char* dev,const char* dev_type, const char* ifcfg_lp, const char* ifcfg_rnmp); + ~TunDevice(); + + short read(u_int8_t* buf, u_int32_t len); + int write(u_int8_t* buf, u_int32_t len); + + const char* getActualName(); + device_type_t getType(); + const char* getTypeString(); + +private: + void operator=(const TunDevice &src); + TunDevice(const TunDevice &src); + + void init_post(); + void do_ifconfig(); + + int fd_; + DeviceConfig conf_; + bool with_type_; + std::string actual_name_; +}; + +#endif diff --git a/src/configure b/src/configure index 9f6ff4b..054069e 100755 --- a/src/configure +++ b/src/configure @@ -12,6 +12,12 @@ case $TARGET in ln -sf linux/tunDevice.cpp ln -sf linux/tunDevice.h ;; + bsd) + rm -rf tunDevice.cpp + rm -rf tunDevice.h + ln -sf bsd/tunDevice.cpp + ln -sf bsd/tunDevice.h + ;; ovpn) rm -rf tunDevice.cpp rm -rf tunDevice.cpp diff --git a/src/linux/tunDevice.cpp b/src/linux/tunDevice.cpp index 8548331..4185bef 100644 --- a/src/linux/tunDevice.cpp +++ b/src/linux/tunDevice.cpp @@ -46,7 +46,9 @@ TunDevice::TunDevice(const char* dev_name, const char* dev_type, const char* ifc { fd_ = ::open(DEFAULT_DEVICE, O_RDWR); if(fd_ < 0) { - std::string msg("can't open device file: "); + std::string msg("can't open device file ("); + msg.append(DEFAULT_DEVICE); + msg.append("): "); msg.append(strerror(errno)); throw std::runtime_error(msg); } |