Merge remote branch 'origin/stable' into stable
[olsrd.git] / src / gateway.c
1 /*
2  * gateway.c
3  *
4  *  Created on: 05.01.2010
5  *      Author: henning
6  */
7
8 #include "common/avl.h"
9 #include "defs.h"
10 #include "ipcalc.h"
11 #include "olsr.h"
12 #include "olsr_cfg.h"
13 #include "olsr_cookie.h"
14 #include "scheduler.h"
15 #include "kernel_routes.h"
16 #include "kernel_tunnel.h"
17 #include "net_os.h"
18 #include "duplicate_set.h"
19 #include "log.h"
20 #include "gateway_default_handler.h"
21 #include "gateway.h"
22
23 #include <assert.h>
24 #include <net/if.h>
25
26 #ifdef LINUX_NETLINK_ROUTING
27 struct avl_tree gateway_tree;
28
29 static struct olsr_cookie_info *gw_mem_cookie = NULL;
30 static uint8_t smart_gateway_netmask[sizeof(union olsr_ip_addr)];
31 static struct gateway_entry *current_ipv4_gw, *current_ipv6_gw;
32 static struct olsr_gw_handler *gw_handler;
33
34 static struct olsr_iptunnel_entry *v4gw_tunnel, *v6gw_tunnel;
35 static bool v4gw_choosen_external, v6gw_choosen_external;
36
37 /**
38  * Reconstructs an uplink/downlink speed value from the encoded
39  * 1 byte transport value (3 bit mantissa, 5 bit exponent)
40  * @param value
41  * @return
42  */
43 static uint32_t
44 deserialize_gw_speed(uint8_t value) {
45   uint32_t speed, exp;
46
47   speed = (value >> 3)+1;
48   exp = value & 7;
49   while (exp-- > 0) {
50     speed *= 10;
51   }
52   return speed;
53 }
54
55 /**
56  * Convert an uplink/downlink speed into an exponential encoded
57  * transport value (1 byte, 3 bit mantissa and 5 bit exponent)
58  * @param value uplink/downlink speed in kbit/s
59  * @return encoded byte value
60  */
61 static uint8_t
62 serialize_gw_speed(uint32_t speed) {
63   uint8_t exp = 0;
64
65   if (speed == 0 || speed > 320000000) {
66     return 0;
67   }
68
69   while (speed > 32 || (speed % 10) == 0) {
70     speed /= 10;
71     exp ++;
72   }
73   return ((speed-1) << 3) | exp;
74 }
75
76 /**
77  * Callback for tunnel interface monitoring which will set the route into the tunnel
78  * when the interface comes up again.
79  * @param if_index
80  * @param ifh
81  * @param flag
82  */
83 static void smartgw_tunnel_monitor (int if_index,
84     struct interface *ifh __attribute__ ((unused)), enum olsr_ifchg_flag flag) {
85   if (current_ipv4_gw != NULL && if_index == v4gw_tunnel->if_index && flag == IFCHG_IF_ADD) {
86     /* v4 tunnel up again, set route */
87     olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, true);
88
89     /* and ip */
90     olsr_os_ifip(v4gw_tunnel->if_index, &olsr_cnf->main_addr, true);
91   }
92   if (current_ipv6_gw != NULL && if_index == v6gw_tunnel->if_index && flag == IFCHG_IF_ADD) {
93     /* v6 status changed, set route */
94     olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, true);
95
96     /* and ip */
97     olsr_os_ifip(v6gw_tunnel->if_index, &olsr_cnf->main_addr, true);
98   }
99 }
100
101 /**
102  * Initialize gateway system
103  */
104 int
105 olsr_init_gateways(void) {
106   gw_mem_cookie = olsr_alloc_cookie("Gateway cookie", OLSR_COOKIE_TYPE_MEMORY);
107   olsr_cookie_set_memory_size(gw_mem_cookie, sizeof(struct gateway_entry));
108
109   avl_init(&gateway_tree, avl_comp_default);
110   current_ipv4_gw = NULL;
111   current_ipv6_gw = NULL;
112
113   v4gw_tunnel = NULL;
114   v6gw_tunnel = NULL;
115
116   refresh_smartgw_netmask();
117
118   if (olsr_os_init_iptunnel()) {
119     return 1;
120   }
121
122   olsr_add_ifchange_handler(smartgw_tunnel_monitor);
123
124   /*
125    * initialize default gateway handler,
126    * can be overwritten with olsr_set_inetgw_handler
127    */
128   olsr_gw_default_init();
129   return 0;
130 }
131
132 void refresh_smartgw_netmask(void) {
133   uint8_t *ip;
134   memset(&smart_gateway_netmask, 0, sizeof(smart_gateway_netmask));
135
136   if (olsr_cnf->smart_gw_active) {
137     union olsr_ip_addr gw_net;
138     memset(&gw_net, 0, sizeof(gw_net));
139
140     ip = (uint8_t *) &smart_gateway_netmask;
141
142     if (olsr_cnf->smart_gw_uplink > 0 || olsr_cnf->smart_gw_downlink > 0) {
143       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_LINKSPEED;
144       ip[GW_HNA_DOWNLINK] = serialize_gw_speed(olsr_cnf->smart_gw_downlink);
145       ip[GW_HNA_UPLINK] = serialize_gw_speed(olsr_cnf->smart_gw_uplink);
146     }
147     if (olsr_cnf->ip_version == AF_INET6 && olsr_cnf->smart_gw_prefix.prefix_len > 0) {
148       ip[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6PREFIX;
149       ip[GW_HNA_V6PREFIXLEN] = olsr_cnf->smart_gw_prefix.prefix_len;
150       memcpy(&ip[GW_HNA_V6PREFIX], &olsr_cnf->smart_gw_prefix.prefix, 8);
151     }
152   }
153 }
154
155 /**
156  * Cleanup gateway tunnel system
157  */
158 void olsr_cleanup_gateways(void) {
159   if (current_ipv4_gw) {
160     olsr_os_del_ipip_tunnel(v4gw_tunnel);
161   }
162   if (current_ipv6_gw) {
163     olsr_os_del_ipip_tunnel(v6gw_tunnel);
164   }
165
166   olsr_remove_ifchange_handler(smartgw_tunnel_monitor);
167   olsr_os_cleanup_iptunnel();
168 }
169
170 /**
171  * Triggers the first lookup of an gateway. This lookup might
172  * take some time to wait for routing/gateway information.
173  */
174 void
175 olsr_trigger_inetgw_startup(void) {
176   gw_handler->handle_startup();
177 }
178
179 /**
180  * Triggers an instant gateway selection based on the current data
181  * @param ipv4 trigger a ipv4 gateway lookup
182  * @param ipv6 trigger a ipv6 gateway lookup
183  * @return 0 if successful, -1 otherwise
184  */
185 int
186 olsr_trigger_inetgw_selection(bool ipv4, bool ipv6) {
187   gw_handler->select_gateway(ipv4, ipv6);
188   return ((ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL)) ? -1 : 0;
189 }
190
191 /**
192  * Triggers a check if the one of the gateways have been lost
193  * through ETX = infinity
194  */
195 void olsr_trigger_gatewayloss_check(void) {
196   struct tc_entry *tc;
197   bool ipv4 = false, ipv6 = false;
198   if (current_ipv4_gw) {
199     tc = olsr_lookup_tc_entry(&current_ipv4_gw->originator);
200     if (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN) {
201       ipv4 = true;
202     }
203   }
204   if (current_ipv6_gw) {
205     tc = olsr_lookup_tc_entry(&current_ipv6_gw->originator);
206     if (tc == NULL || tc->path_cost == ROUTE_COST_BROKEN) {
207       ipv6 = true;
208     }
209   }
210   if (ipv4 || ipv6) {
211     olsr_trigger_inetgw_selection(ipv4, ipv6);
212   }
213 }
214 /**
215  * Set a new gateway handler. Do only call this once during startup from
216  * a plugin to overwrite the default handler.
217  * @param h pointer to gateway handler struct
218  */
219 void
220 olsr_set_inetgw_handler(struct olsr_gw_handler *h) {
221   gw_handler = h;
222 }
223
224 /**
225  * Sets a new internet gateway.
226  * An external set command might trigger an internal one if
227  * address is not a legal gateway.
228  *
229  * @param originator ip address of the node with the new gateway
230  * @param ipv4 set ipv4 gateway
231  * @param ipv6 set ipv6 gateway
232  * @param external true if change was triggered directly by an user,
233  *   false if triggered by automatic lookup.
234  * @return true if an error happened, false otherwise
235  */
236 bool
237 olsr_set_inet_gateway(union olsr_ip_addr *originator, bool ipv4, bool ipv6, bool external) {
238   struct gateway_entry *entry, *oldV4, *oldV6;
239   struct olsr_iptunnel_entry *tunnelV4, *tunnelV6;
240
241   oldV4 = current_ipv4_gw;
242   oldV6 = current_ipv6_gw;
243   tunnelV4 = v4gw_tunnel;
244   tunnelV6 = v6gw_tunnel;
245
246   ipv4 = ipv4 && (olsr_cnf->ip_version == AF_INET || olsr_cnf->use_niit);
247   ipv6 = ipv6 && (olsr_cnf->ip_version == AF_INET6);
248
249   if (ipv4) {
250     current_ipv4_gw = NULL;
251   }
252   if (ipv6) {
253     current_ipv6_gw = NULL;
254   }
255
256   entry = olsr_find_gateway_entry(originator);
257   if (entry != NULL) {
258     if (ipv4 && entry != current_ipv4_gw && entry->ipv4
259         && (!entry->ipv4nat || olsr_cnf->smart_gw_allow_nat)) {
260       /* valid ipv4 gateway */
261       current_ipv4_gw = entry;
262     }
263     if (ipv6 && entry != current_ipv6_gw && entry->ipv6) {
264       /* valid ipv6 gateway */
265       current_ipv6_gw = entry;
266     }
267   }
268
269   /* handle IPv4 */
270   if (oldV4 != current_ipv4_gw) {
271     if ((v4gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv4_gw->originator, true)) != NULL) {
272       olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, true);
273       v4gw_choosen_external = external;
274     }
275     else {
276       // TODO: what to do now ? Choose another one ? Fire up a timer ?
277       current_ipv4_gw = NULL;
278     }
279     if (oldV4 != NULL) {
280       olsr_os_del_ipip_tunnel(tunnelV4);
281     }
282   }
283   /* handle IPv6 */
284   if (oldV6 != current_ipv6_gw) {
285     if ((v6gw_tunnel = olsr_os_add_ipip_tunnel(&current_ipv6_gw->originator, false)) != NULL) {
286       olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, true);
287       v6gw_choosen_external = external;
288     }
289     else {
290       // TODO: what to do now ? Choose another one ? Fire up a timer ?
291       current_ipv6_gw = NULL;
292     }
293     if (oldV6 != NULL) {
294       olsr_os_del_ipip_tunnel(tunnelV6);
295     }
296   }
297   return (ipv4 && current_ipv4_gw == NULL) || (ipv6 && current_ipv6_gw == NULL);
298 }
299
300 /**
301  * returns the gateway_entry of the current ipv4 internet gw.
302  * @return pointer to gateway_entry or NULL if not set
303  */
304 struct gateway_entry *olsr_get_ipv4_inet_gateway(bool *ext) {
305   if (ext) {
306     *ext = v4gw_choosen_external;
307   }
308   return current_ipv4_gw;
309 }
310
311 /**
312  * returns the gateway_entry of the current ipv6 internet gw.
313  * @return pointer to gateway_entry or NULL if not set
314  */
315 struct gateway_entry *olsr_get_ipv6_inet_gateway(bool *ext) {
316   if (ext) {
317     *ext = v6gw_choosen_external;
318   }
319   return current_ipv6_gw;
320 }
321
322 /**
323  * @param originator
324  * @return gateway_entry for corresponding router
325  */
326 struct gateway_entry *
327 olsr_find_gateway_entry(union olsr_ip_addr *originator) {
328   struct avl_node *node = avl_find(&gateway_tree, originator);
329
330   return node == NULL ? NULL : node2gateway(node);
331 }
332
333 /**
334  * update a gateway_entry based on data received from a HNA
335  * @param originator ip of the source of the HNA
336  * @param mask netmask of the HNA
337  * @param prefixlen of the HNA
338  */
339 void
340 olsr_update_gateway_entry(union olsr_ip_addr *originator, union olsr_ip_addr *mask, int prefixlen, uint16_t seqno) {
341   struct gateway_entry *gw;
342   uint8_t *ptr;
343
344   ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
345
346   gw = olsr_find_gateway_entry(originator);
347   if (!gw) {
348     struct ipaddr_str buf;
349     gw = olsr_cookie_malloc(gw_mem_cookie);
350
351     gw->originator = *originator;
352     gw->node.key = &gw->originator;
353
354     avl_insert(&gateway_tree, &gw->node, AVL_DUP_NO);
355   }
356   else if (olsr_seqno_diff(seqno, gw->seqno) <= 0) {
357     /* ignore older HNAs */
358     return;
359   }
360
361   /* keep new HNA seqno */
362   gw->seqno = seqno;
363
364   if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_LINKSPEED) != 0) {
365     gw->uplink = deserialize_gw_speed(ptr[GW_HNA_UPLINK]);
366     gw->downlink = deserialize_gw_speed(ptr[GW_HNA_DOWNLINK]);
367   }
368   else {
369     gw->uplink = 1;
370     gw->downlink = 1;
371   }
372
373   gw->ipv4 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4) != 0;
374   gw->ipv4nat = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV4_NAT) != 0;
375
376   if (olsr_cnf->ip_version == AF_INET6) {
377     gw->ipv6 = (ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6) != 0;
378
379     /* do not reset prefixlength for ::ffff:0:0 HNAs */
380     if (prefixlen == ipv6_internet_route.prefix_len) {
381       memset(&gw->external_prefix, 0, sizeof(gw->external_prefix));
382
383       if ((ptr[GW_HNA_FLAGS] & GW_HNA_FLAG_IPV6PREFIX) != 0
384           && memcmp(mask->v6.s6_addr, &ipv6_internet_route.prefix, olsr_cnf->ipsize) == 0) {
385         /* this is the right prefix (2000::/3), so we can copy the prefix */
386         gw->external_prefix.prefix_len = ptr[GW_HNA_V6PREFIXLEN];
387         memcpy(&gw->external_prefix.prefix, &ptr[GW_HNA_V6PREFIX], 8);
388       }
389     }
390   }
391
392   /* stop cleanup timer if necessary */
393   if (gw->cleanup_timer) {
394     olsr_stop_timer(gw->cleanup_timer);
395     gw->cleanup_timer = NULL;
396   }
397
398   /* call update handler */
399   gw_handler->handle_update_gw(gw);
400 }
401
402 static void cleanup_gateway_handler(void *ptr) {
403   struct gateway_entry *gw = ptr;
404
405   if (gw->ipv4 || gw->ipv6) {
406     return;
407   }
408
409   /* remove gateway entry */
410   avl_delete(&gateway_tree, &gw->node);
411   olsr_cookie_free(gw_mem_cookie, gw);
412 }
413
414 /**
415  * Delete a gateway based on the originator IP and the prefixlength of a HNA.
416  * Should only be called if prefix is a smart_gw prefix or if node is removed
417  * from TC set.
418  * @param originator
419  * @param prefixlen
420  */
421 void
422 olsr_delete_gateway_entry(union olsr_ip_addr *originator, uint8_t prefixlen) {
423   struct gateway_entry *gw;
424   bool change = false;
425   gw = olsr_find_gateway_entry(originator);
426   if (gw && (gw->cleanup_timer == NULL || gw->ipv4 || gw->ipv6)) {
427     if (olsr_cnf->ip_version == AF_INET && prefixlen == 0) {
428       change = gw->ipv4;
429       gw->ipv4 = false;
430       gw->ipv4nat = false;
431     }
432     else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_internet_route.prefix_len) {
433       change = gw->ipv6;
434       gw->ipv6 = false;
435     }
436     else if (olsr_cnf->ip_version == AF_INET6 && prefixlen == ipv6_mappedv4_route.prefix_len) {
437       change = gw->ipv4;
438       gw->ipv4 = false;
439       gw->ipv4nat = false;
440     }
441
442     if (prefixlen == FORCE_DELETE_GW_ENTRY || !(gw->ipv4 || gw->ipv6)) {
443       /* prevent this gateway from being choosen as the new gateway */
444       gw->ipv4 = false;
445       gw->ipv4nat = false;
446       gw->ipv6 = false;
447
448       /* handle gateway loss */
449       gw_handler->handle_delete_gw(gw);
450
451       /* cleanup gateway if necessary */
452       if (current_ipv4_gw == gw) {
453         olsr_os_inetgw_tunnel_route(v4gw_tunnel->if_index, true, false);
454         olsr_os_del_ipip_tunnel(v4gw_tunnel);
455
456         current_ipv4_gw = NULL;
457         v4gw_tunnel = NULL;
458       }
459       if (current_ipv6_gw == gw) {
460         olsr_os_inetgw_tunnel_route(v6gw_tunnel->if_index, false, false);
461         olsr_os_del_ipip_tunnel(v6gw_tunnel);
462
463         current_ipv6_gw = NULL;
464         v6gw_tunnel = NULL;
465       }
466
467       /* remove gateway entry */
468       olsr_set_timer(&gw->cleanup_timer, GW_CLEANUP_INTERVAL, 0, false, cleanup_gateway_handler, gw, NULL);
469     }
470     else if (change) {
471       gw_handler->handle_update_gw(gw);
472     }
473   }
474 }
475
476 /**
477  * Checks if a prefix/netmask combination is a smart gateway
478  * @param prefix
479  * @param mask
480  * @return true if is a valid smart gateway HNA, false otherwise
481  */
482 bool
483 olsr_is_smart_gateway(struct olsr_ip_prefix *prefix, union olsr_ip_addr *mask) {
484   uint8_t *ptr;
485
486   if (!is_prefix_inetgw(prefix)) {
487     return false;
488   }
489
490   ptr = ((uint8_t *)mask) + ((prefix->prefix_len+7)/8);
491   return ptr[GW_HNA_PAD] == 0 && ptr[GW_HNA_FLAGS] != 0;
492 }
493
494 /**
495  * Apply the smart gateway modifications to an outgoing HNA
496  * @param mask pointer to netmask of the HNA
497  * @param prefixlen of the HNA
498  */
499 void
500 olsr_modifiy_inetgw_netmask(union olsr_ip_addr *mask, int prefixlen) {
501   uint8_t *ptr = ((uint8_t *)mask) + ((prefixlen+7)/8);
502
503   memcpy(ptr, &smart_gateway_netmask, sizeof(smart_gateway_netmask) - prefixlen/8);
504   if (olsr_cnf->has_ipv4_gateway) {
505     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4;
506
507     if (olsr_cnf->smart_gw_uplink_nat) {
508       ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV4_NAT;
509     }
510   }
511   if (olsr_cnf->has_ipv6_gateway) {
512     ptr[GW_HNA_FLAGS] |= GW_HNA_FLAG_IPV6;
513   }
514   if (!olsr_cnf->has_ipv6_gateway || prefixlen != ipv6_internet_route.prefix_len){
515     ptr[GW_HNA_FLAGS] &= ~GW_HNA_FLAG_IPV6PREFIX;
516   }
517 }
518
519 /**
520  * Print debug information about gateway entries
521  */
522 void
523 olsr_print_gateway_entries(void) {
524 #ifndef NODEBUG
525   struct ipaddr_str buf;
526   struct gateway_entry *gw;
527   const int addrsize = olsr_cnf->ip_version == AF_INET ? 15 : 39;
528
529   OLSR_PRINTF(0, "\n--- %s ---------------------------------------------------- GATEWAYS\n\n",
530       olsr_wallclock_string());
531   OLSR_PRINTF(0, "%-*s %-6s %-9s %-9s %s\n", addrsize, "IP address", "Type", "Uplink", "Downlink",
532       olsr_cnf->ip_version == AF_INET ? "" : "External Prefix");
533
534   OLSR_FOR_ALL_GATEWAY_ENTRIES(gw) {
535     OLSR_PRINTF(0, "%-*s %s%c%s%c%c %-9u %-9u %s\n", addrsize, olsr_ip_to_string(&buf, &gw->originator),
536         gw->ipv4nat ? "" : "   ",
537         gw->ipv4 ? '4' : ' ',
538         gw->ipv4nat ? "(N)" : "",
539         (gw->ipv4 && gw->ipv6) ? ',' : ' ',
540         gw->ipv6 ? '6' : ' ',
541         gw->uplink, gw->downlink,
542         gw->external_prefix.prefix_len == 0 ? "" : olsr_ip_prefix_to_string(&gw->external_prefix));
543   } OLSR_FOR_ALL_GATEWAY_ENTRIES_END(gw)
544 #endif
545 }
546
547 #endif /* !WIN32 */