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/>.
36 #include <boost/bind.hpp>
37 #include <cerrno> // for ENOMEM
39 #include "datatypes.h"
43 #include "plainPacket.h"
44 #include "encryptedPacket.h"
46 #include "keyDerivation.h"
48 #include "cipherFactory.h"
49 #include "authAlgoFactory.h"
50 #include "keyDerivationFactory.h"
51 #ifndef NOSIGNALCONTROLLER
52 #include "signalController.h"
54 #include "packetSource.h"
55 #include "tunDevice.h"
57 #include "seqWindow.h"
58 #include "connectionList.h"
60 #include "routingTable.h"
61 #include "networkAddress.h"
66 #include "syncQueue.h"
67 #include "syncCommand.h"
68 #include "syncServer.h"
69 #include "syncClient.h"
70 #include "syncOnConnect.hpp"
73 #include "threadParam.h"
74 #define MAX_PACKET_LENGTH 1600
76 #include "cryptinit.hpp"
78 #include "sysexec.hpp"
80 void createConnection(const PacketSourceEndpoint
& remote_end
, window_size_t seqSize
, mux_t mux
)
82 SeqWindow
* seq
= new SeqWindow(seqSize
);
84 KeyDerivation
* kd
= KeyDerivationFactory::create(gOpt
.getKdPrf());
85 kd
->init(gOpt
.getKey(), gOpt
.getSalt());
86 kd
->setLogKDRate(gOpt
.getLdKdr());
87 cLog
.msg(Log::PRIO_NOTICE
) << "added connection remote host " << remote_end
;
89 ConnectionParam
connparam ((*kd
), (*seq
), seq_nr_
, remote_end
);
90 gConnectionList
.addConnection(connparam
,mux
);
92 SyncCommand
sc (gConnectionList
,mux
);
96 if (gOpt
.getIfconfigParamRemoteNetmask() != "")
98 NetworkAddress
addr(gOpt
.getIfconfigParamRemoteNetmask());
99 NetworkPrefix
prefix(addr
,128);
100 gRoutingTable
.addRoute(prefix
,mux
);
101 #ifndef ANYTUN_NOSYNC
102 SyncCommand
sc2 (prefix
);
103 gSyncQueue
.push(sc2
);
109 #ifndef ANYTUN_NOSYNC
110 void syncConnector(void* p
)
112 ThreadParam
* param
= reinterpret_cast<ThreadParam
*>(p
);
114 SyncClient
sc ( param
->connto
.host
, param
->connto
.port
);
118 void syncListener(SyncQueue
* queue
)
122 boost::asio::io_service io_service
;
123 SyncTcpConnection::proto::resolver
resolver(io_service
);
124 SyncTcpConnection::proto::endpoint e
;
125 if(gOpt
.getLocalSyncAddr()!="")
127 SyncTcpConnection::proto::resolver::query
query(gOpt
.getLocalSyncAddr(), gOpt
.getLocalSyncPort());
128 e
= *resolver
.resolve(query
);
130 SyncTcpConnection::proto::resolver::query
query(gOpt
.getLocalSyncPort());
131 e
= *resolver
.resolve(query
);
135 SyncServer
server(io_service
,e
);
136 server
.onConnect
=boost::bind(syncOnConnect
,_1
);
137 queue
->setSyncServerPtr(&server
);
140 catch (std::exception
& e
)
142 std::string addr
= gOpt
.getLocalSyncAddr() == "" ? "*" : gOpt
.getLocalSyncAddr();
143 cLog
.msg(Log::PRIO_ERR
) << "sync: cannot bind to " << addr
<< ":" << gOpt
.getLocalSyncPort()
144 << " (" << e
.what() << ")" << std::endl
;
154 ThreadParam
* param
= reinterpret_cast<ThreadParam
*>(p
);
156 std::auto_ptr
<Cipher
> c(CipherFactory::create(gOpt
.getCipher(), KD_OUTBOUND
));
157 std::auto_ptr
<AuthAlgo
> a(AuthAlgoFactory::create(gOpt
.getAuthAlgo(), KD_OUTBOUND
) );
159 PlainPacket
plain_packet(MAX_PACKET_LENGTH
);
160 EncryptedPacket
encrypted_packet(MAX_PACKET_LENGTH
);
162 u_int16_t mux
= gOpt
.getMux();
163 PacketSourceEndpoint emptyEndpoint
;
166 plain_packet
.setLength(MAX_PACKET_LENGTH
);
167 encrypted_packet
.withAuthTag(false);
168 encrypted_packet
.setLength(MAX_PACKET_LENGTH
);
170 // read packet from device
171 u_int32_t len
= param
->dev
.read(plain_packet
.getPayload(), plain_packet
.getPayloadLength());
172 plain_packet
.setPayloadLength(len
);
174 if(param
->dev
.getType() == TYPE_TUN
)
175 plain_packet
.setPayloadType(PAYLOAD_TYPE_TUN
);
176 else if(param
->dev
.getType() == TYPE_TAP
)
177 plain_packet
.setPayloadType(PAYLOAD_TYPE_TAP
);
179 plain_packet
.setPayloadType(0);
181 if(gConnectionList
.empty())
183 //std::cout << "got Packet for plain "<<plain_packet.getDstAddr().toString();
184 ConnectionMap::iterator cit
;
188 mux
= gRoutingTable
.getRoute(plain_packet
.getDstAddr());
189 //std::cout << " -> "<<mux << std::endl;
190 cit
= gConnectionList
.getConnection(mux
);
192 catch (std::exception
& e
)
194 continue; // no route
197 cit
= gConnectionList
.getBegin();
200 if(cit
==gConnectionList
.getEnd())
201 continue; //no connection
202 ConnectionParam
& conn
= cit
->second
;
204 if(conn
.remote_end_
== emptyEndpoint
)
206 //cLog.msg(Log::PRIO_INFO) << "no remote address set";
211 c
->encrypt(conn
.kd_
, plain_packet
, encrypted_packet
, conn
.seq_nr_
, gOpt
.getSenderId(), mux
);
213 encrypted_packet
.setHeader(conn
.seq_nr_
, gOpt
.getSenderId(), mux
);
216 // add authentication tag
217 a
->generate(conn
.kd_
, encrypted_packet
);
221 param
->src
.send(encrypted_packet
.getBuf(), encrypted_packet
.getLength(), conn
.remote_end_
);
223 catch (std::exception
& e
)
225 // ignoring icmp port unreachable :) and other socket errors :(
229 catch(std::runtime_error
& e
)
231 cLog
.msg(Log::PRIO_ERR
) << "sender thread died due to an uncaught runtime_error: " << e
.what();
233 catch(std::exception
& e
)
235 cLog
.msg(Log::PRIO_ERR
) << "sender thread died due to an uncaught exception: " << e
.what();
239 void receiver(void* p
)
243 ThreadParam
* param
= reinterpret_cast<ThreadParam
*>(p
);
245 std::auto_ptr
<Cipher
> c( CipherFactory::create(gOpt
.getCipher(), KD_INBOUND
) );
246 std::auto_ptr
<AuthAlgo
> a( AuthAlgoFactory::create(gOpt
.getAuthAlgo(), KD_INBOUND
) );
248 EncryptedPacket
encrypted_packet(MAX_PACKET_LENGTH
);
249 PlainPacket
plain_packet(MAX_PACKET_LENGTH
);
253 PacketSourceEndpoint remote_end
;
255 plain_packet
.setLength(MAX_PACKET_LENGTH
);
256 encrypted_packet
.withAuthTag(false);
257 encrypted_packet
.setLength(MAX_PACKET_LENGTH
);
259 // read packet from socket
260 u_int32_t len
= param
->src
.recv(encrypted_packet
.getBuf(), encrypted_packet
.getLength(), remote_end
);
261 encrypted_packet
.setLength(len
);
263 mux_t mux
= encrypted_packet
.getMux();
265 if( gConnectionList
.empty() && gOpt
.getRemoteAddr() == "")
267 cLog
.msg(Log::PRIO_NOTICE
) << "autodetected remote host " << remote_end
;
268 createConnection(remote_end
, gOpt
.getSeqWindowSize(),mux
);
271 ConnectionMap::iterator cit
= gConnectionList
.getConnection(mux
);
272 if (cit
== gConnectionList
.getEnd())
274 ConnectionParam
& conn
= cit
->second
;
276 // check whether auth tag is ok or not
277 if(!a
->checkTag(conn
.kd_
, encrypted_packet
)) {
278 cLog
.msg(Log::PRIO_NOTICE
) << "wrong Authentication Tag!" << std::endl
;
282 //Allow dynamic IP changes
283 //TODO: add command line option to turn this off
284 if (remote_end
!= conn
.remote_end_
)
286 cLog
.msg(Log::PRIO_NOTICE
) << "connection "<< mux
<< " autodetected remote host ip changed " << remote_end
;
287 conn
.remote_end_
=remote_end
;
288 #ifndef ANYTUN_NOSYNC
289 SyncCommand
sc (gConnectionList
,mux
);
295 if(conn
.seq_window_
.checkAndAdd(encrypted_packet
.getSenderId(), encrypted_packet
.getSeqNr()))
297 cLog
.msg(Log::PRIO_NOTICE
) << "Replay attack from " << conn
.remote_end_
298 << " seq:"<< encrypted_packet
.getSeqNr() << " sid: "<< encrypted_packet
.getSenderId();
303 c
->decrypt(conn
.kd_
, encrypted_packet
, plain_packet
);
305 // check payload_type
306 if((param
->dev
.getType() == TYPE_TUN
&& plain_packet
.getPayloadType() != PAYLOAD_TYPE_TUN4
&&
307 plain_packet
.getPayloadType() != PAYLOAD_TYPE_TUN6
) ||
308 (param
->dev
.getType() == TYPE_TAP
&& plain_packet
.getPayloadType() != PAYLOAD_TYPE_TAP
))
311 // write it on the device
312 param
->dev
.write(plain_packet
.getPayload(), plain_packet
.getLength());
315 catch(std::runtime_error
& e
)
317 cLog
.msg(Log::PRIO_ERR
) << "sender thread died due to an uncaught runtime_error: " << e
.what();
319 catch(std::exception
& e
)
321 cLog
.msg(Log::PRIO_ERR
) << "receiver thread died due to an uncaught exception: " << e
.what();
326 int main(int argc
, char* argv
[])
328 bool daemonized
=false;
331 cLog
.msg(Log::PRIO_NOTICE
) << "anytun started...";
332 /// std::cout << "anytun - secure anycast tunneling protocol" << std::endl;
333 int32_t result
= gOpt
.parse(argc
, argv
);
336 std::cerr
<< "syntax error near: " << argv
[result
] << std::endl
<< std::endl
;
337 cLog
.msg(Log::PRIO_ERR
) << "syntax error, exitting";
340 std::cerr
<< "can't parse host-port definition" << std::endl
<< std::endl
;
341 cLog
.msg(Log::PRIO_ERR
) << "can't parse host-port definition, exitting";
349 std::ofstream pidFile
;
350 if(gOpt
.getPidFile() != "") {
351 pidFile
.open(gOpt
.getPidFile().c_str());
352 if(!pidFile
.is_open()) {
353 std::cout
<< "can't open pid file" << std::endl
;
358 #ifndef USE_SSL_CRYPTO
359 // this must be called before any other libgcrypt call
365 TunDevice
dev(gOpt
.getDevName(), gOpt
.getDevType(), gOpt
.getIfconfigParamLocal(), gOpt
.getIfconfigParamRemoteNetmask());
366 cLog
.msg(Log::PRIO_NOTICE
) << "dev created (opened)";
367 cLog
.msg(Log::PRIO_NOTICE
) << "dev opened - actual name is '" << dev
.getActualName() << "'";
368 cLog
.msg(Log::PRIO_NOTICE
) << "dev type is '" << dev
.getTypeString() << "'";
370 if(gOpt
.getPostUpScript() != "") {
371 int postup_ret
= execScript(gOpt
.getPostUpScript(), dev
.getActualName());
372 cLog
.msg(Log::PRIO_NOTICE
) << "post up script '" << gOpt
.getPostUpScript() << "' returned " << postup_ret
;
377 if(gOpt
.getLocalAddr() == "")
378 src
= new UDPPacketSource(gOpt
.getLocalPort());
380 src
= new UDPPacketSource(gOpt
.getLocalAddr(), gOpt
.getLocalPort());
382 ConnectToList connect_to
= gOpt
.getConnectTo();
385 if(gOpt
.getRemoteAddr() != "")
387 boost::asio::io_service io_service
;
388 UDPPacketSource::proto::resolver
resolver(io_service
);
389 UDPPacketSource::proto::resolver::query
query(gOpt
.getRemoteAddr(), gOpt
.getRemotePort());
390 UDPPacketSource::proto::endpoint endpoint
= *resolver
.resolve(query
);
391 createConnection(endpoint
,gOpt
.getSeqWindowSize(), gOpt
.getMux());
394 RouteList routes
= gOpt
.getRoutes();
395 RouteList::const_iterator rit
;
396 for(rit
= routes
.begin(); rit
!= routes
.end(); ++rit
)
398 NetworkAddress
addr( rit
->net_addr
);
399 NetworkPrefix
prefix( addr
, static_cast<u_int8_t
>(rit
->prefix_length
));
400 gRoutingTable
.addRoute( prefix
, gOpt
.getMux() );
402 if (connect_to
.begin() == connect_to
.end() && routes
.begin() == routes
.end() && gOpt
.getDevType()=="tun")
404 std::cout
<< "No Routes and no syncronisation hosts have be specified"<< std::endl
;
405 std::cout
<< "anytun won't be able to send any data"<< std::endl
;
406 std::cout
<< "most likely you want to add --route 0.0.0.0/0 --route ::/0"<< std::endl
;
407 std::cout
<< "to your command line to allow both ipv4 and ipv6 traffic"<< std::endl
;
408 std::cout
<< "(this does not set operating system routes, use the post-up script"<< std::endl
;
409 std::cout
<< " to set them)"<< std::endl
;
414 chrootAndDrop(gOpt
.getChrootDir(), gOpt
.getUsername());
415 if(gOpt
.getDaemonize())
421 if(pidFile
.is_open()) {
422 pid_t pid
= getpid();
428 #ifndef NOSIGNALCONTROLLER
429 SignalController sig
;
433 OptionConnectTo
* connTo
= new OptionConnectTo();
434 ThreadParam
p(dev
, *src
, *connTo
);
436 boost::thread
senderThread(boost::bind(sender
,&p
));
437 #ifndef NOSIGNALCONTROLLER
438 boost::thread
receiverThread(boost::bind(receiver
,&p
));
440 #ifndef ANYTUN_NOSYNC
441 boost::thread
* syncListenerThread
;
442 if(gOpt
.getLocalSyncPort() != "")
443 syncListenerThread
= new boost::thread(boost::bind(syncListener
,&queue
));
445 std::list
<boost::thread
*> connectThreads
;
446 for(ConnectToList::iterator it
= connect_to
.begin() ;it
!= connect_to
.end(); ++it
) {
447 ThreadParam
* point
= new ThreadParam(dev
, *src
, *it
);
448 connectThreads
.push_back(new boost::thread(boost::bind(syncConnector
,point
)));
452 #ifndef NOSIGNALCONTROLLER
458 // TODO cleanup threads here!
460 pthread_cancel(senderThread);
461 pthread_cancel(receiverThread);
462 #ifndef ANYTUN_NOSYNC
463 if ( gOpt.getLocalSyncPort())
464 pthread_cancel(syncListenerThread);
465 for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it)
469 pthread_join(senderThread, NULL);
470 pthread_join(receiverThread, NULL);
471 #ifndef ANYTUN_NOSYNC
472 if ( gOpt.getLocalSyncPort())
473 pthread_join(syncListenerThread, NULL);
475 for( std::list<pthread_t>::iterator it = connectThreads.begin() ;it != connectThreads.end(); ++it)
476 pthread_join(*it, NULL);
485 catch(std::runtime_error
& e
)
487 cLog
.msg(Log::PRIO_ERR
) << "uncaught runtime error, exiting: " << e
.what();
490 std::cout
<< "uncaught runtime error, exiting: " << e
.what() << std::endl
;
493 catch(std::exception
& e
)
495 cLog
.msg(Log::PRIO_ERR
) << "uncaught exception, exiting: " << e
.what();
498 std::cout
<< "uncaught exception, exiting: " << e
.what() << std::endl
;