b683dca0d5d5dad5286ffe8b5e0af53787d08c97
[anytun.git] / src / routingTable.cpp
1 /*
2  *  anytun
3  *
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.
12  *
13  *
14  *  Copyright (C) 2007-2008 Othmar Gsenger, Erwin Nindl, 
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
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.
22  *
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.
27  *
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/>.
30  */
31 #include "networkPrefix.h"
32 #include "threadUtils.hpp"
33 #include "datatypes.h"
34 #include "anytunError.h"
35
36 #include "routingTable.h"
37 #include "routingTree.hpp"
38
39 RoutingTable* RoutingTable::inst = NULL;
40 Mutex RoutingTable::instMutex;
41 RoutingTable& gRoutingTable = RoutingTable::instance();
42
43
44 RoutingTable& RoutingTable::instance()
45 {
46   Lock lock(instMutex);
47   static instanceCleaner c;
48   if(!inst)
49     inst = new RoutingTable();
50
51   return *inst;
52 }
53
54 RoutingTable::RoutingTable()
55 {
56 }
57
58 RoutingTable::~RoutingTable()
59 {
60
61
62 void RoutingTable::updateRouteTreeUnlocked(const NetworkPrefix & pref)
63 {
64   //Lock lock(mutex_); //deadlock
65
66         u_int8_t length=pref.getNetworkPrefixLength();
67         network_address_type_t type=pref.getNetworkAddressType();
68         u_int16_t mux = routes_[pref.getNetworkAddressType()].find(pref)->second;
69         RoutingTreeNode * node = &(root_[type]);
70         if (type==ipv4)
71         {
72                 ipv4_bytes_type bytes(pref.to_bytes_v4());
73                 if (length>32)
74                         length=32;
75                 RoutingTree::walk(bytes, node, length, mux);
76         } else if  (type==ipv6) {
77                 ipv6_bytes_type bytes(pref.to_bytes_v6());
78                 if (length>128)
79                         length=128;
80                 RoutingTree::walk(bytes, node, length, mux);
81         } else if (type==ethernet) {
82                 ethernet_bytes_type bytes(pref.to_bytes_ethernet());
83                 if (length>48)
84                         length=48;
85                 RoutingTree::walk(bytes, node, length, mux);
86         } else {
87                 AnytunError::throwErr() << "illegal protocol type";     
88         }
89         //root_[type].print(0);
90 }
91
92 void RoutingTable::addRoute(const NetworkPrefix & pref, u_int16_t mux)
93 {
94   Lock lock(mutex_);
95         
96         network_address_type_t type=pref.getNetworkAddressType();       
97
98         if (type==ipv4 || type==ipv6)
99         {
100     std::pair<RoutingMap::iterator, bool> ret = routes_[type].insert(RoutingMap::value_type(pref,mux));
101     if(!ret.second)
102     {
103       routes_[pref.getNetworkAddressType()].erase(ret.first);
104       routes_[pref.getNetworkAddressType()].insert(RoutingMap::value_type(pref,mux));
105     }
106                 root_[pref.getNetworkAddressType()]=RoutingTreeNode();
107                 RoutingMap::iterator it = routes_[type].begin();
108           for (;it!=routes_[pref.getNetworkAddressType()].end();++it)
109                         updateRouteTreeUnlocked(it->first);
110         } else if (type==ethernet) {
111     return; // TODO: add support for ethernet
112         } else {
113                 AnytunError::throwErr() << "illegal protocol type";     
114         }
115 }
116
117
118 void RoutingTable::delRoute(const NetworkPrefix & pref )
119 {
120   Lock lock(mutex_);
121         
122   routes_[pref.getNetworkAddressType()].erase(routes_[pref.getNetworkAddressType()].find(pref));        
123 }
124
125 u_int16_t RoutingTable::getRoute(const NetworkAddress & addr)
126 {
127         Lock lock(mutex_);
128         network_address_type_t type=addr.getNetworkAddressType();
129         
130         if (routes_[type].empty())
131         AnytunError::throwErr() << "no route";
132
133         if (type==ipv4)
134         {
135                 ipv4_bytes_type bytes(addr.to_bytes_v4());
136                 return RoutingTree::find(bytes, root_[type]);
137         } else if  (type==ipv6) {
138                 ipv6_bytes_type bytes(addr.to_bytes_v6());
139                 return RoutingTree::find(bytes, root_[type]);
140         } else if (type==ethernet) {
141                 //TODO Our model wont fit to ethernet addresses well.
142                 // maybe use hashmap or something like that instead
143                 ethernet_bytes_type bytes(addr.to_bytes_ethernet());
144                 return RoutingTree::find(bytes, root_[type]);
145         } else {
146                 AnytunError::throwErr() << "illegal protocol type";     
147         }
148   return 0;
149 }
150
151 u_int16_t* RoutingTable::getOrNewRoutingTEUnlocked(const NetworkPrefix & addr)
152 {
153   RoutingMap::iterator it = routes_[addr.getNetworkAddressType()].find(addr);
154   if(it!=routes_[addr.getNetworkAddressType()].end())
155     return &(it->second);
156
157   routes_[addr.getNetworkAddressType()].insert(RoutingMap::value_type(addr, 1));
158   it = routes_[addr.getNetworkAddressType()].find(addr);
159   return &(it->second);
160 }
161
162 u_int16_t RoutingTable::getCountUnlocked(network_address_type_t type)
163 {
164         RoutingMap::iterator it = routes_[type].begin();
165         u_int16_t routes=0;
166         for (;it!=routes_[type].end();++it)
167                 routes++;
168         return routes;
169 }
170
171 RoutingMap::iterator RoutingTable::getBeginUnlocked(network_address_type_t type)
172 {
173         return routes_[type].begin();
174 }
175
176 RoutingMap::iterator RoutingTable::getEndUnlocked(network_address_type_t type)
177 {
178         return routes_[type].end();
179 }
180
181 void RoutingTable::clear(network_address_type_t type)
182 {
183   Lock lock(mutex_);
184         routes_[type].clear();
185 }
186
187 bool RoutingTable::empty(network_address_type_t type)
188 {
189   Lock lock(mutex_);
190         return routes_[type].empty();
191 }
192
193 Mutex& RoutingTable::getMutex()
194 {
195   return mutex_;
196 }