4 * The secure anycast tunneling protocol (satp) defines a protocol used
5 * for communication between any combination of unicast and anycast
6 * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel
7 * mode and allows tunneling of every ETHER TYPE protocol (e.g.
8 * ethernet, ip, arp ...). satp directly includes cryptography and
9 * message authentication based on the methods used by SRTP. It is
10 * intended to deliver a generic, scaleable and secure solution for
11 * tunneling and relaying of packets of any protocol.
14 * Copyright (C) 2007-2014 Markus Grüneis, Othmar Gsenger, Erwin Nindl,
15 * Christian Pointner <satp@wirdorange.org>
17 * This file is part of Anytun.
19 * Anytun is free software: you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation, either version 3 of the License, or
24 * Anytun is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with Anytun. If not, see <http://www.gnu.org/licenses/>.
32 * In addition, as a special exception, the copyright holders give
33 * permission to link the code of portions of this program with the
34 * OpenSSL library under certain conditions as described in each
35 * individual source file, and distribute linked combinations
37 * You must obey the GNU General Public License in all respects
38 * for all of the code used other than OpenSSL. If you modify
39 * file(s) with this exception, you may extend this exception to your
40 * version of the file(s), but you are not obligated to do so. If you
41 * do not wish to do so, delete this exception statement from your
42 * version. If you delete this exception statement from all source
43 * files in the program, then also delete it here.
46 #include <boost/bind.hpp>
47 #include <boost/thread.hpp>
48 #include <boost/assign.hpp>
49 #include <boost/scoped_ptr.hpp>
53 #include "datatypes.h"
58 #include "plainPacket.h"
59 #include "encryptedPacket.h"
61 #include "keyDerivation.h"
63 #include "cipherFactory.h"
64 #include "authAlgoFactory.h"
65 #include "keyDerivationFactory.h"
66 #include "signalController.h"
67 #if !defined(_MSC_VER) && !defined(MINGW)
68 # include "daemonService.h"
71 # include "win32/winService.h"
73 # include "nullDaemon.h"
76 #include "packetSource.h"
77 #include "tunDevice.h"
79 #include "seqWindow.h"
80 #include "connectionList.h"
82 #include "routingTable.h"
83 #include "networkAddress.h"
87 #include "syncQueue.h"
88 #include "syncCommand.h"
89 #include "syncServer.h"
90 #include "syncClient.h"
91 #include "syncOnConnect.hpp"
94 #include "cryptinit.hpp"
97 bool disableRouting = false;
99 void createConnection(const PacketSourceEndpoint& remote_end, window_size_t seqSize, mux_t mux)
101 SeqWindow* seq = new SeqWindow(seqSize);
103 KeyDerivation* kd = KeyDerivationFactory::create(gOpt.getKdPrf());
104 kd->init(gOpt.getKey(), gOpt.getSalt(), gOpt.getPassphrase());
105 kd->setRole(gOpt.getRole());
106 cLog.msg(Log::PRIO_NOTICE) << "added connection remote host " << remote_end;
108 ConnectionParam connparam((*kd), (*seq), seq_nr_, remote_end);
109 gConnectionList.addConnection(connparam,mux);
110 #ifndef ANYTUN_NOSYNC
111 SyncCommand sc(gConnectionList,mux);
116 void createConnectionResolver(PacketSourceResolverIt it, window_size_t seqSize, mux_t mux)
118 createConnection(*it, seqSize, mux);
121 void createConnectionError(const std::exception& e)
123 gSignalController.inject(SIGERROR, e.what());
126 #ifndef ANYTUN_NOSYNC
127 void syncConnector(const OptionHost& connto)
129 SyncClient sc(connto.addr, connto.port);
136 SyncServer server(gOpt.getLocalSyncAddr(), gOpt.getLocalSyncPort(), boost::bind(syncOnConnect, _1));
137 gSyncQueue.setSyncServerPtr(&server);
139 } catch(std::runtime_error& e) {
140 cLog.msg(Log::PRIO_ERROR) << "sync listener thread died due to an uncaught runtime_error: " << e.what();
141 } catch(std::exception& e) {
142 cLog.msg(Log::PRIO_ERROR) << "sync listener thread died due to an uncaught exception: " << e.what();
147 void sender(TunDevice* dev, PacketSource* src)
150 cLog.msg(Log::PRIO_ERROR) << "sender thread died because either dev or src pointer is null";
155 boost::scoped_ptr<Cipher> c(CipherFactory::create(gOpt.getCipher(), KD_OUTBOUND));
156 boost::scoped_ptr<AuthAlgo> a(AuthAlgoFactory::create(gOpt.getAuthAlgo(), KD_OUTBOUND));
158 PlainPacket plain_packet(MAX_PACKET_LENGTH);
159 EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH, gOpt.getAuthTagLength());
161 uint16_t mux = gOpt.getMux();
162 PacketSourceEndpoint emptyEndpoint;
164 plain_packet.setLength(MAX_PACKET_LENGTH);
165 encrypted_packet.withAuthTag(false);
166 encrypted_packet.setLength(MAX_PACKET_LENGTH);
168 // read packet from device
169 int len = dev->read(plain_packet.getPayload(), plain_packet.getPayloadLength());
171 continue; // silently ignore device read errors, this is probably no good idea...
174 if(static_cast<uint32_t>(len) < PlainPacket::getHeaderLength()) {
175 continue; // ignore short packets
177 plain_packet.setPayloadLength(len);
179 if(dev->getType() == TYPE_TUN) {
180 plain_packet.setPayloadType(PAYLOAD_TYPE_TUN);
181 } else if(dev->getType() == TYPE_TAP) {
182 plain_packet.setPayloadType(PAYLOAD_TYPE_TAP);
184 plain_packet.setPayloadType(0);
187 if(gConnectionList.empty()) {
190 //std::cout << "got Packet for plain "<<plain_packet.getDstAddr().toString();
191 ConnectionMap::iterator cit;
195 mux = gRoutingTable.getRoute(plain_packet.getDstAddr());
196 //std::cout << " -> "<<mux << std::endl;
197 cit = gConnectionList.getConnection(mux);
198 } catch(std::exception&) { continue; } // no route
200 cit = gConnectionList.getBegin();
203 cit = gConnectionList.getBegin();
206 if(cit==gConnectionList.getEnd()) {
207 continue; //no connection
209 ConnectionParam& conn = cit->second;
211 if(conn.remote_end_ == emptyEndpoint) {
212 //cLog.msg(Log::PRIO_INFO) << "no remote address set";
217 c->encrypt(conn.kd_, plain_packet, encrypted_packet, conn.seq_nr_, gOpt.getSenderId(), mux);
219 encrypted_packet.setHeader(conn.seq_nr_, gOpt.getSenderId(), mux);
222 // add authentication tag
223 a->generate(conn.kd_, encrypted_packet);
226 src->send(encrypted_packet.getBuf(), encrypted_packet.getLength(), conn.remote_end_);
227 } catch(std::exception& /*e*/) {
228 //TODO: do something here
229 //cLog.msg(Log::PRIO_ERROR) << "could not send data: " << e.what();
232 } catch(std::runtime_error& e) {
233 cLog.msg(Log::PRIO_ERROR) << "sender thread died due to an uncaught runtime_error: " << e.what();
234 } catch(std::exception& e) {
235 cLog.msg(Log::PRIO_ERROR) << "sender thread died due to an uncaught exception: " << e.what();
239 void receiver(TunDevice* dev, PacketSource* src)
242 cLog.msg(Log::PRIO_ERROR) << "receiver thread died because either dev or src pointer is null";
247 boost::scoped_ptr<Cipher> c(CipherFactory::create(gOpt.getCipher(), KD_INBOUND));
248 boost::scoped_ptr<AuthAlgo> a(AuthAlgoFactory::create(gOpt.getAuthAlgo(), KD_INBOUND));
250 uint32_t auth_tag_length = gOpt.getAuthTagLength();
251 EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH, auth_tag_length);
252 PlainPacket plain_packet(MAX_PACKET_LENGTH);
255 PacketSourceEndpoint remote_end;
257 plain_packet.setLength(MAX_PACKET_LENGTH);
258 encrypted_packet.withAuthTag(false);
259 encrypted_packet.setLength(MAX_PACKET_LENGTH);
261 // read packet from socket
264 len = src->recv(encrypted_packet.getBuf(), encrypted_packet.getLength(), remote_end);
265 } catch(std::exception& /*e*/) {
266 //TODO: do something here
267 //cLog.msg(Log::PRIO_ERROR) << "could not recive packet "<< e.what();
271 continue; // silently ignore socket recv errors, this is probably no good idea...
274 if(static_cast<uint32_t>(len) < (EncryptedPacket::getHeaderLength() + auth_tag_length)) {
275 continue; // ignore short packets
277 encrypted_packet.setLength(len);
279 mux_t mux = encrypted_packet.getMux();
281 if(gConnectionList.empty() && gOpt.getRemoteAddr() == "") {
282 cLog.msg(Log::PRIO_NOTICE) << "autodetected remote host " << remote_end;
283 createConnection(remote_end, gOpt.getSeqWindowSize(),mux);
286 ConnectionMap::iterator cit = gConnectionList.getConnection(mux);
287 if(cit == gConnectionList.getEnd()) {
290 ConnectionParam& conn = cit->second;
292 // check whether auth tag is ok or not
293 if(!a->checkTag(conn.kd_, encrypted_packet)) {
294 cLog.msg(Log::PRIO_NOTICE) << "wrong Authentication Tag!";
299 if(conn.seq_window_.checkAndAdd(encrypted_packet.getSenderId(), encrypted_packet.getSeqNr())) {
300 cLog.msg(Log::PRIO_NOTICE) << "Replay attack from " << conn.remote_end_
301 << " seq:"<< encrypted_packet.getSeqNr() << " sid: "<< encrypted_packet.getSenderId();
305 //Allow dynamic IP changes
306 //TODO: add command line option to turn this off
307 if(remote_end != conn.remote_end_) {
308 cLog.msg(Log::PRIO_NOTICE) << "connection "<< mux << " autodetected remote host ip changed " << remote_end;
309 conn.remote_end_=remote_end;
310 #ifndef ANYTUN_NOSYNC
311 SyncCommand sc(gConnectionList,mux);
315 // ignore zero length packets
316 if(encrypted_packet.getPayloadLength() <= PlainPacket::getHeaderLength()) {
321 c->decrypt(conn.kd_, encrypted_packet, plain_packet);
323 // check payload_type
324 if((dev->getType() == TYPE_TUN && plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN4 &&
325 plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN6) ||
326 (dev->getType() == TYPE_TAP && plain_packet.getPayloadType() != PAYLOAD_TYPE_TAP)) {
330 // write it on the device
331 dev->write(plain_packet.getPayload(), plain_packet.getLength());
333 } catch(std::runtime_error& e) {
334 cLog.msg(Log::PRIO_ERROR) << "receiver thread died due to an uncaught runtime_error: " << e.what();
335 } catch(std::exception& e) {
336 cLog.msg(Log::PRIO_ERROR) << "receiver thread died due to an uncaught exception: " << e.what();
340 void startSendRecvThreads(TunDevice* dev, PacketSource* src)
342 src->waitUntilReady();
344 boost::thread(boost::bind(sender, dev, src));
345 boost::thread(boost::bind(receiver, dev, src));
350 int main(int argc, char* argv[])
354 if(std::string(argv[1]) == "install") {
355 WinService::install();
357 } else if(std::string(argv[1]) == "uninstall") {
358 WinService::uninstall();
364 } catch(std::runtime_error& e) {
365 std::cout << "caught runtime error, exiting: " << e.what() << std::endl;
366 } catch(std::exception& e) {
367 std::cout << "caught exception, exiting: " << e.what() << std::endl;
371 int real_main(int argc, char* argv[], WinService& service)
374 int main(int argc, char* argv[])
376 DaemonService service;
380 if(!gOpt.parse(argc, argv)) {
384 StringList targets = gOpt.getLogTargets();
385 for(StringList::const_iterator it = targets.begin(); it != targets.end(); ++it) {
388 } catch(syntax_error& e) {
389 std::cerr << e << std::endl;
394 cLog.msg(Log::PRIO_NOTICE) << "anytun started...";
395 gOpt.parse_post(); // print warnings
397 // daemonizing has to done before any thread gets started
398 service.initPrivs(gOpt.getUsername(), gOpt.getGroupname());
399 if(gOpt.getDaemonize()) {
403 OptionNetwork net = gOpt.getIfconfigParam();
404 TunDevice dev(gOpt.getDevName(), gOpt.getDevType(), net.net_addr, net.prefix_length);
405 cLog.msg(Log::PRIO_NOTICE) << "dev opened - name '" << dev.getActualName() << "', node '" << dev.getActualNode() << "'";
406 cLog.msg(Log::PRIO_NOTICE) << "dev type is '" << dev.getTypeString() << "'";
408 SysExec* postup_script = NULL;
409 if(gOpt.getPostUpScript() != "") {
410 cLog.msg(Log::PRIO_NOTICE) << "executing post-up script '" << gOpt.getPostUpScript() << "'";
411 StringVector args = boost::assign::list_of(dev.getActualName())(dev.getActualNode());
412 postup_script = new SysExec(gOpt.getPostUpScript(), args);
415 if(gOpt.getChrootDir() != "") {
417 service.chroot(gOpt.getChrootDir());
418 } catch(const std::runtime_error& e) {
419 cLog.msg(Log::PRIO_WARNING) << "ignoring chroot error: " << e.what();
424 // this has to be called before the first thread is started
425 gSignalController.init(service);
427 boost::thread(boost::bind(&TunDevice::waitUntilReady,&dev));
429 boost::thread(boost::bind(&SysExec::waitAndDestroy,postup_script));
434 PacketSource* src = new UDPPacketSource(gOpt.getLocalAddr(), gOpt.getLocalPort());
436 if(gOpt.getRemoteAddr() != "") {
437 gResolver.resolveUdp(gOpt.getRemoteAddr(), gOpt.getRemotePort(), boost::bind(createConnectionResolver, _1, gOpt.getSeqWindowSize(), gOpt.getMux()), boost::bind(createConnectionError, _1), gOpt.getResolvAddrType());
440 HostList connect_to = gOpt.getRemoteSyncHosts();
442 NetworkList routes = gOpt.getRoutes();
443 NetworkList::const_iterator rit;
444 for(rit = routes.begin(); rit != routes.end(); ++rit) {
445 NetworkAddress addr(rit->net_addr);
446 NetworkPrefix prefix(addr, static_cast<uint8_t>(rit->prefix_length));
447 gRoutingTable.addRoute(prefix, gOpt.getMux());
449 if(connect_to.begin() == connect_to.end() || gOpt.getDevType()!="tun") {
450 cLog.msg(Log::PRIO_NOTICE) << "No sync/control host defined or not a tun device. Disabling multi connection support (routing)";
455 #ifndef ANYTUN_NOSYNC
456 boost::thread* syncListenerThread = NULL;
457 if(gOpt.getLocalSyncPort() != "") {
458 syncListenerThread = new boost::thread(boost::bind(syncListener));
459 if(syncListenerThread) syncListenerThread->detach();
462 boost::thread_group connectThreads;
463 for(HostList::const_iterator it = connect_to.begin() ; it != connect_to.end(); ++it) {
464 connectThreads.create_thread(boost::bind(syncConnector, *it));
468 // wait for packet source to finish in a seperate thread in order
469 // to be still able to process signals while waiting
470 boost::thread(boost::bind(startSendRecvThreads, &dev, src));
472 int ret = gSignalController.run();
474 // TODO: stop all threads and cleanup
481 } catch(std::runtime_error& e) {
482 cLog.msg(Log::PRIO_ERROR) << "uncaught runtime error, exiting: " << e.what();
483 if(!service.isDaemonized()) {
484 std::cout << "uncaught runtime error, exiting: " << e.what() << std::endl;
486 } catch(std::exception& e) {
487 cLog.msg(Log::PRIO_ERROR) << "uncaught exception, exiting: " << e.what();
488 if(!service.isDaemonized()) {
489 std::cout << "uncaught exception, exiting: " << e.what() << std::endl;