added compile time options NOCRYPT,NODAEMON,NOEXEC for easyier windows porting
[anytun.git] / src / anytun.cpp
blob553c4512550c181f1bc0269b8caf76cc33030ac2
1 /*
2 * anytun
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 methodes 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-2008 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 version 3 as
21 * published by the Free Software Foundation.
23 * Anytun is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with anytun. If not, see <http://www.gnu.org/licenses/>.
32 #include <iostream>
33 #include <fstream>
34 #include <poll.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <grp.h>
38 #include <sys/wait.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
42 #include <boost/bind.hpp>
43 #ifndef NOCRYPT
44 #include <gcrypt.h>
45 #endif
46 #include <cerrno> // for ENOMEM
48 #include "datatypes.h"
50 #include "log.h"
51 #include "buffer.h"
52 #include "plainPacket.h"
53 #include "encryptedPacket.h"
54 #include "cipher.h"
55 #include "keyDerivation.h"
56 #include "authAlgo.h"
57 #include "cipherFactory.h"
58 #include "authAlgoFactory.h"
59 #include "keyDerivationFactory.h"
60 #include "signalController.h"
61 #include "packetSource.h"
62 #include "tunDevice.h"
63 #include "options.h"
64 #include "seqWindow.h"
65 #include "connectionList.h"
66 #include "routingTable.h"
67 #include "networkAddress.h"
69 #include "syncQueue.h"
70 #include "syncCommand.h"
72 #ifndef ANYTUN_NOSYNC
73 #include "syncServer.h"
74 #include "syncClient.h"
75 #include "syncOnConnect.hpp"
76 #endif
78 #include "threadParam.h"
79 #define MAX_PACKET_LENGTH 1600
81 #include "cryptinit.hpp"
82 #include "daemon.hpp"
83 #include "sysexec.hpp"
85 #define SESSION_KEYLEN_AUTH 20 // TODO: hardcoded size
86 #define SESSION_KEYLEN_ENCR 16 // TODO: hardcoded size
87 #define SESSION_KEYLEN_SALT 14 // TODO: hardcoded size
89 void createConnection(const PacketSourceEndpoint & remote_end, ConnectionList & cl, u_int16_t seqSize, SyncQueue & queue, mux_t mux)
91 SeqWindow * seq= new SeqWindow(seqSize);
92 seq_nr_t seq_nr_=0;
93 KeyDerivation * kd = KeyDerivationFactory::create(gOpt.getKdPrf());
94 kd->init(gOpt.getKey(), gOpt.getSalt());
95 cLog.msg(Log::PRIO_NOTICE) << "added connection remote host " << remote_end;
97 ConnectionParam connparam ( (*kd), (*seq), seq_nr_, remote_end);
98 cl.addConnection(connparam,mux);
99 NetworkAddress addr(ipv4,gOpt.getIfconfigParamRemoteNetmask().c_str());
100 NetworkPrefix prefix(addr,32);
101 gRoutingTable.addRoute(prefix,mux);
102 SyncCommand sc (cl,mux);
103 queue.push(sc);
104 SyncCommand sc2 (prefix);
105 queue.push(sc2);
108 bool checkPacketSeqNr(EncryptedPacket& pack,ConnectionParam& conn)
110 // compare sender_id and seq with window
111 if(conn.seq_window_.hasSeqNr(pack.getSenderId(), pack.getSeqNr()))
113 cLog.msg(Log::PRIO_NOTICE) << "Replay attack from " << conn.remote_end_
114 << " seq:"<<pack.getSeqNr() << " sid: "<<pack.getSenderId();
115 return false;
118 conn.seq_window_.addSeqNr(pack.getSenderId(), pack.getSeqNr());
119 return true;
122 void sender(void* p)
124 try
126 ThreadParam* param = reinterpret_cast<ThreadParam*>(p);
128 std::auto_ptr<Cipher> c(CipherFactory::create(gOpt.getCipher()));
129 std::auto_ptr<AuthAlgo> a(AuthAlgoFactory::create(gOpt.getAuthAlgo()) );
131 PlainPacket plain_packet(MAX_PACKET_LENGTH);
132 EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH);
134 Buffer session_key(u_int32_t(SESSION_KEYLEN_ENCR)); // TODO: hardcoded size
135 Buffer session_salt(u_int32_t(SESSION_KEYLEN_SALT)); // TODO: hardcoded size
136 Buffer session_auth_key(u_int32_t(SESSION_KEYLEN_AUTH)); // TODO: hardcoded size
138 //TODO replace mux
139 u_int16_t mux = gOpt.getMux();
140 PacketSourceEndpoint emptyEndpoint;
141 while(1)
143 plain_packet.setLength(MAX_PACKET_LENGTH);
144 encrypted_packet.withAuthTag(false);
145 encrypted_packet.setLength(MAX_PACKET_LENGTH);
147 // read packet from device
148 u_int32_t len = param->dev.read(plain_packet.getPayload(), plain_packet.getPayloadLength());
149 plain_packet.setPayloadLength(len);
150 // set payload type
151 if(param->dev.getType() == TYPE_TUN)
152 plain_packet.setPayloadType(PAYLOAD_TYPE_TUN);
153 else if(param->dev.getType() == TYPE_TAP)
154 plain_packet.setPayloadType(PAYLOAD_TYPE_TAP);
155 else
156 plain_packet.setPayloadType(0);
158 if(param->cl.empty())
159 continue;
160 //std::cout << "got Packet for plain "<<plain_packet.getDstAddr().toString();
161 mux = gRoutingTable.getRoute(plain_packet.getDstAddr());
162 //std::cout << " -> "<<mux << std::endl;
163 ConnectionMap::iterator cit = param->cl.getConnection(mux);
164 if(cit==param->cl.getEnd())
165 continue;
166 ConnectionParam & conn = cit->second;
168 if(conn.remote_end_ == emptyEndpoint)
170 //cLog.msg(Log::PRIO_INFO) << "no remote address set";
171 continue;
174 // generate packet-key TODO: do this only when needed
175 conn.kd_.generate(LABEL_SATP_ENCRYPTION, conn.seq_nr_, session_key);
176 conn.kd_.generate(LABEL_SATP_SALT, conn.seq_nr_, session_salt);
178 c->setKey(session_key);
179 c->setSalt(session_salt);
181 // encrypt packet
182 c->encrypt(plain_packet, encrypted_packet, conn.seq_nr_, gOpt.getSenderId(), mux);
184 encrypted_packet.setHeader(conn.seq_nr_, gOpt.getSenderId(), mux);
185 conn.seq_nr_++;
187 // add authentication tag
188 if(a->getMaxLength()) {
189 encrypted_packet.addAuthTag();
190 conn.kd_.generate(LABEL_SATP_MSG_AUTH, encrypted_packet.getSeqNr(), session_auth_key);
191 a->setKey(session_auth_key);
192 a->generate(encrypted_packet);
196 param->src.send(encrypted_packet.getBuf(), encrypted_packet.getLength(), conn.remote_end_);
198 catch (std::exception& e)
200 // ignoring icmp port unreachable :) and other socket errors :(
204 catch(std::runtime_error& e)
206 cLog.msg(Log::PRIO_ERR) << "sender thread died due to an uncaught runtime_error: " << e.what();
208 catch(std::exception& e)
210 cLog.msg(Log::PRIO_ERR) << "sender thread died due to an uncaught exception: " << e.what();
214 #ifndef ANYTUN_NOSYNC
215 void syncConnector(void* p )
217 ThreadParam* param = reinterpret_cast<ThreadParam*>(p);
219 SyncClient sc ( param->connto.host, param->connto.port);
220 sc.run();
223 void syncListener(SyncQueue * queue)
227 boost::asio::io_service io_service;
228 SyncTcpConnection::proto::resolver resolver(io_service);
229 SyncTcpConnection::proto::endpoint e;
230 if(gOpt.getLocalSyncAddr()!="")
232 SyncTcpConnection::proto::resolver::query query(gOpt.getLocalSyncAddr(), gOpt.getLocalSyncPort());
233 e = *resolver.resolve(query);
234 } else {
235 SyncTcpConnection::proto::resolver::query query(gOpt.getLocalSyncPort());
236 e = *resolver.resolve(query);
240 SyncServer server(io_service,e);
241 server.onConnect=boost::bind(syncOnConnect,_1);
242 queue->setSyncServerPtr(&server);
243 io_service.run();
245 catch (std::exception& e)
247 std::string addr = gOpt.getLocalSyncAddr() == "" ? "*" : gOpt.getLocalSyncAddr();
248 cLog.msg(Log::PRIO_ERR) << "sync: cannot bind to " << addr << ":" << gOpt.getLocalSyncPort()
249 << " (" << e.what() << ")" << std::endl;
253 #endif
255 void receiver(void* p)
259 ThreadParam* param = reinterpret_cast<ThreadParam*>(p);
261 std::auto_ptr<Cipher> c( CipherFactory::create(gOpt.getCipher()) );
262 std::auto_ptr<AuthAlgo> a( AuthAlgoFactory::create(gOpt.getAuthAlgo()) );
264 EncryptedPacket encrypted_packet(MAX_PACKET_LENGTH);
265 PlainPacket plain_packet(MAX_PACKET_LENGTH);
267 Buffer session_key(u_int32_t(SESSION_KEYLEN_ENCR)); // TODO: hardcoded size
268 Buffer session_salt(u_int32_t(SESSION_KEYLEN_SALT)); // TODO: hardcoded size
269 Buffer session_auth_key(u_int32_t(SESSION_KEYLEN_AUTH)); // TODO: hardcoded size
271 while(1)
273 PacketSourceEndpoint remote_end;
275 plain_packet.setLength(MAX_PACKET_LENGTH);
276 encrypted_packet.withAuthTag(false);
277 encrypted_packet.setLength(MAX_PACKET_LENGTH);
279 // read packet from socket
280 u_int32_t len = param->src.recv(encrypted_packet.getBuf(), encrypted_packet.getLength(), remote_end);
281 encrypted_packet.setLength(len);
283 mux_t mux = encrypted_packet.getMux();
284 // autodetect peer
285 if( param->cl.empty() && gOpt.getRemoteAddr() == "")
287 cLog.msg(Log::PRIO_NOTICE) << "autodetected remote host " << remote_end;
288 createConnection(remote_end, param->cl, gOpt.getSeqWindowSize(),param->queue,mux);
291 ConnectionMap::iterator cit = param->cl.getConnection(mux);
292 if (cit == param->cl.getEnd())
293 continue;
294 ConnectionParam & conn = cit->second;
296 // check whether auth tag is ok or not
297 if(a->getMaxLength()) {
298 encrypted_packet.withAuthTag(true);
299 conn.kd_.generate(LABEL_SATP_MSG_AUTH, encrypted_packet.getSeqNr(), session_auth_key);
300 a->setKey(session_auth_key);
301 if(!a->checkTag(encrypted_packet)) {
302 cLog.msg(Log::PRIO_NOTICE) << "wrong Authentication Tag!" << std::endl;
303 continue;
305 encrypted_packet.removeAuthTag();
308 //Allow dynamic IP changes
309 //TODO: add command line option to turn this off
310 if (remote_end != conn.remote_end_)
312 cLog.msg(Log::PRIO_NOTICE) << "connection "<< mux << " autodetected remote host ip changed " << remote_end;
313 conn.remote_end_=remote_end;
314 SyncCommand sc (param->cl,mux);
315 param->queue.push(sc);
318 // Replay Protection
319 if (!checkPacketSeqNr(encrypted_packet, conn))
320 continue;
322 // generate packet-key
323 conn.kd_.generate(LABEL_SATP_ENCRYPTION, encrypted_packet.getSeqNr(), session_key);
324 conn.kd_.generate(LABEL_SATP_SALT, encrypted_packet.getSeqNr(), session_salt);
325 c->setKey(session_key);
326 c->setSalt(session_salt);
328 // decrypt packet
329 c->decrypt(encrypted_packet, plain_packet);
331 // check payload_type
332 if((param->dev.getType() == TYPE_TUN && plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN4 &&
333 plain_packet.getPayloadType() != PAYLOAD_TYPE_TUN6) ||
334 (param->dev.getType() == TYPE_TAP && plain_packet.getPayloadType() != PAYLOAD_TYPE_TAP))
335 continue;
337 // write it on the device
338 param->dev.write(plain_packet.getPayload(), plain_packet.getLength());
341 catch(std::runtime_error& e)
343 cLog.msg(Log::PRIO_ERR) << "sender thread died due to an uncaught runtime_error: " << e.what();
345 catch(std::exception& e)
347 cLog.msg(Log::PRIO_ERR) << "receiver thread died due to an uncaught exception: " << e.what();
352 int main(int argc, char* argv[])
354 bool daemonized=false;
355 try
358 // std::cout << "anytun - secure anycast tunneling protocol" << std::endl;
359 if(!gOpt.parse(argc, argv)) {
360 gOpt.printUsage();
361 exit(-1);
364 cLog.msg(Log::PRIO_NOTICE) << "anytun started...";
366 std::ofstream pidFile;
367 if(gOpt.getPidFile() != "") {
368 pidFile.open(gOpt.getPidFile().c_str());
369 if(!pidFile.is_open()) {
370 std::cout << "can't open pid file" << std::endl;
374 TunDevice dev(gOpt.getDevName(), gOpt.getDevType(), gOpt.getIfconfigParamLocal(), gOpt.getIfconfigParamRemoteNetmask());
375 cLog.msg(Log::PRIO_NOTICE) << "dev created (opened)";
376 cLog.msg(Log::PRIO_NOTICE) << "dev opened - actual name is '" << dev.getActualName() << "'";
377 cLog.msg(Log::PRIO_NOTICE) << "dev type is '" << dev.getTypeString() << "'";
378 #ifndef NOEXEC
379 if(gOpt.getPostUpScript() != "") {
380 int postup_ret = execScript(gOpt.getPostUpScript(), dev.getActualName());
381 cLog.msg(Log::PRIO_NOTICE) << "post up script '" << gOpt.getPostUpScript() << "' returned " << postup_ret;
383 #endif
385 PacketSource* src;
386 if(gOpt.getLocalAddr() == "")
387 src = new UDPPacketSource(gOpt.getLocalPort());
388 else
389 src = new UDPPacketSource(gOpt.getLocalAddr(), gOpt.getLocalPort());
391 ConnectionList & cl (gConnectionList);
392 ConnectToList connect_to = gOpt.getConnectTo();
393 SyncQueue queue;
395 if(gOpt.getRemoteAddr() != "")
397 boost::asio::io_service io_service;
398 UDPPacketSource::proto::resolver resolver(io_service);
399 UDPPacketSource::proto::resolver::query query(gOpt.getRemoteAddr(), gOpt.getRemotePort());
400 UDPPacketSource::proto::endpoint endpoint = *resolver.resolve(query);
401 createConnection(endpoint,cl,gOpt.getSeqWindowSize(), queue, gOpt.getMux());
404 #ifndef NODAEMON
405 if(gOpt.getChroot())
406 chrootAndDrop(gOpt.getChrootDir(), gOpt.getUsername());
407 if(gOpt.getDaemonize())
409 daemonize();
410 daemonized = true;
412 #endif
414 if(pidFile.is_open()) {
415 pid_t pid = getpid();
416 pidFile << pid;
417 pidFile.close();
420 SignalController sig;
421 sig.init();
423 ThreadParam p(dev, *src, cl, queue,*(new OptionConnectTo()));
425 #ifndef NOCRYPT
426 // this must be called before any other libgcrypt call
427 if(!initLibGCrypt())
428 return -1;
429 #endif
431 boost::thread senderThread(boost::bind(sender,&p));
432 boost::thread receiverThread(boost::bind(receiver,&p));
433 #ifndef ANYTUN_NOSYNC
434 boost::thread * syncListenerThread;
435 if(gOpt.getLocalSyncPort() != "")
436 syncListenerThread = new boost::thread(boost::bind(syncListener,&queue));
438 std::list<boost::thread *> connectThreads;
439 for(ConnectToList::iterator it = connect_to.begin() ;it != connect_to.end(); ++it) {
440 ThreadParam * point = new ThreadParam(dev, *src, cl, queue,*it);
441 connectThreads.push_back(new boost::thread(boost::bind(syncConnector,point)));
443 #endif
445 int ret = sig.run();
447 return ret;
448 // TODO cleanup here!
450 pthread_cancel(senderThread);
451 pthread_cancel(receiverThread);
452 #ifndef ANYTUN_NOSYNC
453 if ( gOpt.getLocalSyncPort())
454 pthread_cancel(syncListenerThread);
455 for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it)
456 pthread_cancel(*it);
457 #endif
459 pthread_join(senderThread, NULL);
460 pthread_join(receiverThread, NULL);
461 #ifndef ANYTUN_NOSYNC
462 if ( gOpt.getLocalSyncPort())
463 pthread_join(syncListenerThread, NULL);
465 for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it)
466 pthread_join(*it, NULL);
467 #endif
468 delete src;
469 delete &p.connto;
471 return ret;
474 catch(std::runtime_error& e)
476 if(daemonized)
477 cLog.msg(Log::PRIO_ERR) << "uncaught runtime error, exiting: " << e.what();
478 else
479 std::cout << "uncaught runtime error, exiting: " << e.what() << std::endl;
481 catch(std::exception& e)
483 if(daemonized)
484 cLog.msg(Log::PRIO_ERR) << "uncaught exception, exiting: " << e.what();
485 else
486 std::cout << "uncaught exception, exiting: " << e.what() << std::endl;