From 6c7ccd96ee77a2a374c6a6ccc9805412198b27f7 Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Sun, 11 May 2008 00:24:15 +0000 Subject: added device for bsd tested under openbsd but should work on freebsd and netbsd as well TODO: do_ifconfig --- src/anytun.cpp | 539 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 284 insertions(+), 255 deletions(-) (limited to 'src/anytun.cpp') 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(p); - - std::auto_ptr c(CipherFactory::create(gOpt.getCipher())); - std::auto_ptr 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(p); - //TODO replace mux - u_int16_t mux = gOpt.getMux(); - while(1) + std::auto_ptr c(CipherFactory::create(gOpt.getCipher())); + std::auto_ptr 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 "< "<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 "< "<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(p); - - std::auto_ptr c( CipherFactory::create(gOpt.getCipher()) ); - std::auto_ptr 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(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 c( CipherFactory::create(gOpt.getCipher()) ); + std::auto_ptr 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 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 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::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it) - pthread_cancel(*it); + if ( gOpt.getLocalSyncPort()) + pthread_cancel(syncListenerThread); + for( std::list::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::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it) - pthread_join(*it, NULL); + if ( gOpt.getLocalSyncPort()) + pthread_join(syncListenerThread, NULL); + + for( std::list::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; + } } - + + -- cgit v1.2.3