5f2d849f4e699ad5179b1476cfbb0eddf5c960e6
[oonf.git] / src-plugins / subsystems / oonf_interface.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <netinet/in.h>
43
44 #include "common/common_types.h"
45 #include "common/avl.h"
46 #include "common/avl_comp.h"
47 #include "common/list.h"
48 #include "common/netaddr.h"
49 #include "common/netaddr_acl.h"
50 #include "common/string.h"
51
52 #include "core/oonf_cfg.h"
53 #include "core/oonf_logging.h"
54 #include "core/oonf_main.h"
55 #include "core/oonf_subsystem.h"
56 #include "subsystems/oonf_class.h"
57 #include "subsystems/oonf_timer.h"
58 #include "subsystems/os_interface.h"
59 #include "subsystems/os_socket.h"
60 #include "subsystems/os_system.h"
61
62 #include "subsystems/oonf_interface.h"
63
64 /* Definitions */
65 #define LOG_INTERFACE _oonf_interface_subsystem.logging
66
67 /* timeinterval to delay change in interface to trigger actions */
68 #define OONF_INTERFACE_CHANGE_INTERVAL 100
69
70 /* prototypes */
71 static int _init(void);
72 static void _cleanup(void);
73 static void _early_cfg_init(void);
74
75 static const struct netaddr *_get_fixed_prefix(
76     int af_type, struct netaddr_acl *filter);
77 static const struct netaddr *_get_exact_match_bindaddress(
78     int af_type, struct netaddr_acl *filter, struct os_interface_data *ifdata);
79 static const struct netaddr *_get_matching_bindaddress(
80     int af_type, struct netaddr_acl *filter, struct os_interface_data *ifdata);
81
82 static struct os_interface *_interface_add(const char *, bool mesh);
83 static void _interface_remove(struct os_interface *interf, bool mesh);
84 static int _handle_unused_parameter(const char *);
85 static void _cb_change_handler(void *);
86 static void _trigger_change_timer(struct os_interface *);
87
88 /* global tree of known interfaces */
89 static struct avl_tree _oonf_interface_tree;
90
91 /* subsystem definition */
92 static const char *_dependencies[] = {
93   OONF_CLASS_SUBSYSTEM,
94   OONF_TIMER_SUBSYSTEM,
95   OONF_OS_SYSTEM_SUBSYSTEM,
96   OONF_OS_INTERFACE_SUBSYSTEM,
97   OONF_OS_SOCKET_SUBSYSTEM,
98 };
99
100 static struct oonf_subsystem _oonf_interface_subsystem = {
101   .name = OONF_INTERFACE_SUBSYSTEM,
102   .dependencies = _dependencies,
103   .dependencies_count = ARRAYSIZE(_dependencies),
104   .early_cfg_init = _early_cfg_init,
105   .init = _init,
106   .cleanup = _cleanup,
107 };
108 DECLARE_OONF_PLUGIN(_oonf_interface_subsystem);
109
110 static struct list_entity _interface_listener;
111 static struct oonf_timer_class _change_timer_info = {
112   .name = "Interface change",
113   .callback = _cb_change_handler,
114 };
115
116 static struct os_interface_if_listener _iflistener = {
117   .if_changed = oonf_interface_trigger_change,
118 };
119
120 static struct oonf_class _if_class = {
121   .name = OONF_CLASS_INTERFACE,
122   .size = sizeof(struct os_interface),
123 };
124
125 /**
126  * Initialize interface subsystem
127  * @return always returns 0
128  */
129 static int
130 _init(void) {
131   /* initialize data structures */
132   oonf_timer_add(&_change_timer_info);
133   oonf_class_add(&_if_class);
134
135   avl_init(&_oonf_interface_tree, avl_comp_strcasecmp, false);
136   list_init_head(&_interface_listener);
137
138   os_interface_listener_add(&_iflistener);
139   return 0;
140 }
141
142 /**
143  * Cleanup interface subsystem
144  */
145 static void
146 _cleanup(void) {
147   struct oonf_interface_listener *listener, *l_it;
148
149   list_for_each_element_safe(&_interface_listener, listener, _node, l_it) {
150     oonf_interface_remove_listener(listener);
151   }
152
153   os_interface_listener_remove(&_iflistener);
154   oonf_class_remove(&_if_class);
155   oonf_timer_remove(&_change_timer_info);
156 }
157
158 static
159 void _early_cfg_init(void) {
160   oonf_main_set_parameter_handler(_handle_unused_parameter);
161 }
162
163 /**
164  * Add a listener to a specific interface
165  * @param listener initialized listener object
166  * @return -1 if an error happened, 0 otherwise
167  */
168 int
169 oonf_interface_add_listener(
170     struct oonf_interface_listener *listener) {
171   if (list_is_node_added(&listener->_node)) {
172     return 0;
173   }
174
175   OONF_DEBUG(LOG_INTERFACE, "Add listener for interface %s", listener->name);
176
177   if (listener->name) {
178     listener->interface = _interface_add(listener->name, listener->mesh);
179     if (listener->interface == NULL) {
180       return -1;
181     }
182   }
183
184   list_add_tail(&_interface_listener, &listener->_node);
185   return 0;
186 }
187
188 /**
189  * Removes a listener to an interface object
190  * @param listener pointer to listener object
191  */
192 void
193 oonf_interface_remove_listener(
194     struct oonf_interface_listener *listener) {
195   if (!list_is_node_added(&listener->_node)) {
196     return;
197   }
198
199   OONF_DEBUG(LOG_INTERFACE, "Remove listener for interface %s", listener->name);
200
201   if (listener->interface) {
202     _interface_remove(listener->interface, listener->mesh);
203   }
204
205   list_remove(&listener->_node);
206 }
207
208 /**
209  * Trigger a potential change in the interface settings. Normally
210  * called by os_system code
211  * @param name interface name
212  * @param down true if interface is going down
213  */
214 void
215 oonf_interface_trigger_change(unsigned if_index, bool down) {
216   char if_name[IF_NAMESIZE];
217   struct os_interface *interf = NULL, *if_ptr;
218
219   if (if_indextoname(if_index, if_name) != NULL) {
220     interf = avl_find_element(&_oonf_interface_tree, if_name, interf, _node);
221   }
222
223   if (interf == NULL) {
224     avl_for_each_element(&_oonf_interface_tree, if_ptr, _node) {
225       if (if_ptr->data.index == if_index) {
226         interf = if_ptr;
227       }
228     }
229   }
230
231   if (interf == NULL) {
232     OONF_INFO(LOG_INTERFACE, "Unknown interface update: %d", if_index);
233     return;
234   }
235   if (down) {
236     interf->data.up = false;
237   }
238
239   oonf_interface_trigger_handler(interf);
240 }
241
242 /**
243  * Trigger the interface change handler after a short waiting period
244  * to accumulate multiple change events.
245  * @param interf pointer to olsr interface
246  */
247 void
248 oonf_interface_trigger_handler(struct os_interface *interf) {
249   /* trigger interface reload in 100 ms */
250   OONF_DEBUG(LOG_INTERFACE, "Change of interface %s was triggered", interf->data.name);
251
252   _trigger_change_timer(interf);
253 }
254
255 /**
256  * @param name interface name
257  * @param buf optional pointer to helper buffer, if not NULL and the
258  *   interface data wasn't cached, it will be read into the helper
259  *   buffer directly.
260  * @return pointer to olsr interface data, NULL if not found
261  */
262 struct os_interface_data *
263 oonf_interface_get_data(const char *name, struct os_interface_data *buf) {
264   struct os_interface *interf;
265
266   interf = avl_find_element(&_oonf_interface_tree, name, interf, _node);
267   if (interf == NULL) {
268     if (buf) {
269       if (os_interface_update(buf, name)) {
270         return NULL;
271       }
272       return buf;
273     }
274     return NULL;
275   }
276
277   return &interf->data;
278 }
279
280 /**
281  * Search for an interface by its index
282  * @param ifindex index of the interface
283  * @return interface data, NULL if not found
284  */
285 struct os_interface_data *
286 oonf_interface_get_data_by_ifindex(unsigned ifindex) {
287   struct os_interface *interf;
288
289   avl_for_each_element(&_oonf_interface_tree, interf, _node) {
290     if (interf->data.index == ifindex) {
291       return &interf->data;
292     }
293   }
294   return NULL;
295 }
296
297 /**
298  * Search for an interface by its base-index
299  * @param ifindex index of the interface
300  * @return first fitting interface data, NULL if not found
301  */
302 struct os_interface_data *
303 oonf_interface_get_data_by_ifbaseindex(unsigned ifindex) {
304   struct os_interface *interf;
305
306   avl_for_each_element(&_oonf_interface_tree, interf, _node) {
307     if (interf->data.base_index == ifindex) {
308       return &interf->data;
309     }
310   }
311   return NULL;
312 }
313
314 /**
315  * Get the prefix of an interface fitting to a destination address
316  * @param destination destination address
317  * @param ifdata interface data, NULL to search over all interfaces
318  * @return network prefix (including full host), NULL if not found
319  */
320 const struct netaddr *
321 oonf_interface_get_prefix_from_dst(
322     struct netaddr *destination, struct os_interface_data *ifdata) {
323   struct os_interface *interf;
324   const struct netaddr *result;
325   size_t i;
326 #ifdef OONF_LOG_DEBUG_INFO
327   struct netaddr_str nbuf1, nbuf2;
328 #endif
329
330   if (ifdata == NULL) {
331     avl_for_each_element(&_oonf_interface_tree, interf, _node) {
332       result = oonf_interface_get_prefix_from_dst(destination, &interf->data);
333       if (result) {
334         return result;
335       }
336     }
337     return NULL;
338   }
339
340   for (i=0; i<ifdata->prefixcount; i++) {
341     if (netaddr_is_in_subnet(&ifdata->prefixes[i], destination)) {
342       OONF_DEBUG(LOG_INTERFACE, "destination %s query matched if prefix: %s",
343           netaddr_to_string(&nbuf1, destination),
344           netaddr_to_string(&nbuf2, &ifdata->prefixes[i]));
345
346       return &ifdata->prefixes[i];
347     }
348   }
349
350   return NULL;
351 }
352
353 /**
354  * Calculate the IP address a socket should bind to
355  * @param filter filter for IP address to bind on
356  * @param ifdata interface to bind to socket on, NULL if not
357  *   bound to an interface.
358  * @return 0 if an IP was calculated, -1 otherwise
359  */
360 const struct netaddr *
361 oonf_interface_get_bindaddress(int af_type,
362     struct netaddr_acl *filter, struct os_interface_data *ifdata) {
363   const struct netaddr *result;
364   size_t i;
365 #ifdef OONF_LOG_DEBUG_INFO
366   struct netaddr_str nbuf;
367 #endif
368
369   OONF_DEBUG(LOG_INTERFACE, "Find bindto (%s) for acl (if=%s):",
370       af_type == AF_INET ? "ipv4" : "ipv6",
371       !ifdata ? "any" : ifdata->name);
372
373   for (i=0; i<filter->accept_count; i++) {
374     OONF_DEBUG_NH(LOG_INTERFACE, "\taccept: %s", netaddr_to_string(&nbuf, &filter->accept[i]));
375   }
376   for (i=0; i<filter->reject_count; i++) {
377     OONF_DEBUG_NH(LOG_INTERFACE, "\treject: %s", netaddr_to_string(&nbuf, &filter->reject[i]));
378   }
379   OONF_DEBUG_NH(LOG_INTERFACE, "\t%s_first, %s_default",
380       filter->reject_first ? "reject" : "accept",
381       filter->accept_default ? "accept" : "reject");
382
383   result = NULL;
384   if (ifdata == NULL) {
385     OONF_DEBUG(LOG_INTERFACE, "Look for fixed prefix");
386     result = _get_fixed_prefix(af_type, filter);
387   }
388   if (!result) {
389     OONF_DEBUG(LOG_INTERFACE, "Look for exact match");
390     result = _get_exact_match_bindaddress(af_type, filter, ifdata);
391   }
392   if (!result) {
393     OONF_DEBUG(LOG_INTERFACE, "Look for prefix match");
394     result = _get_matching_bindaddress(af_type, filter, ifdata);
395   }
396   OONF_DEBUG_NH(LOG_INTERFACE, "Bind to '%s'", netaddr_to_string(&nbuf, result));
397   return result;
398 }
399
400 struct avl_tree *
401 oonf_interface_get_tree(void) {
402   return &_oonf_interface_tree;
403 }
404
405 /**
406  * Checks if the whole ACL is one maximum length address
407  * (or two, one for each possible address type).
408  * @param af_type requested address family
409  * @param filter filter to parse
410  * @return pointer to address to bind socket to, NULL if no match
411  */
412 static const struct netaddr *
413 _get_fixed_prefix(int af_type, struct netaddr_acl *filter) {
414   const struct netaddr *first, *second;
415   if (filter->reject_count > 0) {
416     return NULL;
417   }
418
419   if (filter->accept_count == 0 || filter->accept_count > 2) {
420     return NULL;
421   }
422
423   first = &filter->accept[0];
424   if (netaddr_get_prefix_length(first) != netaddr_get_maxprefix(first)) {
425     return NULL;
426   }
427
428   if (filter->accept_count == 2) {
429     second = &filter->accept[1];
430
431     if (netaddr_get_address_family(first) ==
432         netaddr_get_address_family(second)) {
433       /* must be two different address families */
434       return NULL;
435     }
436
437     if (netaddr_get_prefix_length(second) != netaddr_get_maxprefix(second)) {
438       return NULL;
439     }
440     if (netaddr_get_address_family(second) == af_type) {
441       return second;
442     }
443   }
444
445   if (netaddr_get_address_family(first) == af_type) {
446     return first;
447   }
448   return NULL;
449 }
450
451 /**
452  * Finds an IP on an/all interfaces that matches an exact (maximum length)
453  * filter rule
454  *
455  * @param af_type address family type to look for
456  * @param filter filter that must be matched
457  * @param ifdata interface to look through, NULL for all interfaces
458  * @return pointer to address to bind socket to, NULL if no match
459  */
460 static const struct netaddr *
461 _get_exact_match_bindaddress(int af_type, struct netaddr_acl *filter,
462     struct os_interface_data *ifdata) {
463   struct os_interface *interf;
464   const struct netaddr *result;
465   size_t i,j;
466
467   /* handle the 'all interfaces' case */
468   if (ifdata == NULL) {
469     avl_for_each_element(&_oonf_interface_tree, interf, _node) {
470       if ((result = _get_exact_match_bindaddress(af_type, filter, &interf->data)) != NULL) {
471         return result;
472       }
473     }
474     return NULL;
475   }
476
477   /* run through all filters */
478   for (i=0; i<filter->accept_count; i++) {
479     /* look for maximum prefix length filters */
480     if (netaddr_get_prefix_length(&filter->accept[i]) != netaddr_get_af_maxprefix(af_type)) {
481       continue;
482     }
483
484     /* run through all interface addresses and look for match */
485     for (j=0; j<ifdata->addrcount; j++) {
486       if (netaddr_cmp(&ifdata->addresses[j], &filter->accept[i]) == 0) {
487         return &filter->accept[i];
488       }
489     }
490   }
491
492   /* no exact match found */
493   return NULL;
494 }
495
496 /**
497  * Finds an IP on an/all interfaces that matches a filter rule
498  *
499  * @param af_type address family type to look for
500  * @param filter filter that must be matched
501  * @param ifdata interface to look through, NULL for all interfaces
502  * @return pointer to address to bind socket to, NULL if no match
503  */
504 static const struct netaddr *
505 _get_matching_bindaddress(int af_type, struct netaddr_acl *filter,
506     struct os_interface_data *ifdata) {
507   struct os_interface *interf;
508   const struct netaddr *result;
509   size_t i;
510
511   /* handle the 'all interfaces' case */
512   if (ifdata == NULL) {
513     avl_for_each_element(&_oonf_interface_tree, interf, _node) {
514       if ((result = _get_matching_bindaddress(af_type, filter, &interf->data)) != NULL) {
515         return result;
516       }
517     }
518     return NULL;
519   }
520
521   /* run through interface address list looking for filter match */
522   for (i=0; i<ifdata->addrcount; i++) {
523     if (netaddr_get_address_family(&ifdata->addresses[i]) != af_type) {
524       continue;
525     }
526
527     if (netaddr_acl_check_accept(filter, &ifdata->addresses[i])) {
528       return &ifdata->addresses[i];
529     }
530   }
531   return NULL;
532 }
533
534 /**
535  * Add an interface to the listener system
536  * @param if_index index of interface
537  * @param mesh true if interface is used for mesh traffic
538  * @return pointer to interface struct, NULL if an error happened
539  */
540 static struct os_interface *
541 _interface_add(const char *name, bool mesh) {
542   struct os_interface *interf;
543
544   interf = avl_find_element(&_oonf_interface_tree, name, interf, _node);
545   if (!interf) {
546     /* allocate new interface */
547     interf = oonf_class_malloc(&_if_class);
548     if (interf == NULL) {
549       return NULL;
550     }
551
552     /* hookup */
553     strscpy(interf->data.name, name, sizeof(interf->data.name));
554     interf->_node.key = interf->data.name;
555     avl_insert(&_oonf_interface_tree, &interf->_node);
556
557     interf->data.index = if_nametoindex(name);
558
559     interf->_change_timer.class = &_change_timer_info;
560     interf->_change_timer.cb_context = interf;
561
562     /* initialize data of interface */
563     os_interface_update(&interf->data, name);
564   }
565
566   /* update reference counters */
567   interf->usage_counter++;
568   if(mesh) {
569     if (interf->mesh_counter == 0) {
570       os_interface_init_mesh(interf);
571     }
572     interf->mesh_counter++;
573   }
574
575   OONF_INFO(LOG_INTERFACE, "interface '%s' has reference count %u", name, interf->usage_counter);
576
577   /* trigger update */
578   if (interf->usage_counter == 1) {
579     /* new interface */
580     _cb_change_handler(interf);
581   }
582   else {
583     /* existing one, delay update */
584     _trigger_change_timer(interf);
585   }
586
587   return interf;
588 }
589
590 /**
591  * Remove an interface from the listener system. If multiple listeners
592  * share an interface, this will only decrease the reference counter.
593  * @param interf pointer to os_interface
594  */
595 static void
596 _interface_remove(struct os_interface *interf, bool mesh) {
597   /* handle mesh interface flag */
598   if (mesh) {
599     interf->mesh_counter--;
600
601     if (interf->mesh_counter < 1) {
602       /* no mesh interface anymore, remove routing settings */
603       os_interface_cleanup_mesh(interf);
604     }
605   }
606
607   interf->usage_counter--;
608   OONF_INFO(LOG_INTERFACE, "Interface '%s' has reference count %u", interf->data.name, interf->usage_counter);
609
610   if (interf->usage_counter > 0) {
611     return;
612   }
613
614   if (interf->data.addresses) {
615     free(interf->data.addresses);
616   }
617   avl_remove(&_oonf_interface_tree, &interf->_node);
618
619   oonf_timer_stop(&interf->_change_timer);
620   oonf_class_free(&_if_class, interf);
621 }
622
623 /**
624  * Timer callback to handle potential change of data of an interface
625  * @param ptr pointer to interface object
626  */
627 static void
628 _cb_change_handler(void *ptr) {
629   struct os_interface_data old_data, new_data;
630   struct oonf_interface_listener *listener, *l_it;
631   struct os_interface *interf;
632
633   interf = ptr;
634
635   OONF_DEBUG(LOG_INTERFACE, "Change of interface %s in progress", interf->data.name);
636
637   /* read interface data */
638   memset(&new_data, 0, sizeof(new_data));
639   if (os_interface_update(&new_data, interf->data.name)) {
640     /* an error happened, try again */
641     OONF_INFO(LOG_INTERFACE, "Could not query os network interface %s, trying again soon",
642         interf->data.name);
643     _trigger_change_timer(interf);
644     return;
645   }
646
647   /* something changed ?
648   if (memcmp(&interf->data, &new_data, sizeof(new_data)) == 0) {
649     return;
650   }
651 */
652   /* copy data to interface object, but remember the old data */
653   memcpy(&old_data, &interf->data, sizeof(old_data));
654   memcpy(&interf->data, &new_data, sizeof(interf->data));
655
656   /* call listeners */
657   list_for_each_element_safe(&_interface_listener, listener, _node, l_it) {
658     if (listener->process != NULL
659         && (listener->name == NULL
660             || strcasecmp(listener->name, interf->data.name) == 0)) {
661       listener->old = &old_data;
662       listener->process(listener);
663       listener->old = NULL;
664     }
665   }
666
667   if (old_data.addresses) {
668     free (old_data.addresses);
669   }
670 }
671
672 /**
673  * Activate the change timer of an interface object
674  * @param interf pointer to interface object
675  */
676 static void
677 _trigger_change_timer(struct os_interface *interf) {
678   oonf_timer_set(&interf->_change_timer, OONF_INTERFACE_CHANGE_INTERVAL);
679 }
680
681 static int
682 _handle_unused_parameter(const char *arg) {
683   cfg_db_add_namedsection(oonf_cfg_get_rawdb(), CFG_INTERFACE_SECTION, arg);
684   return 0;
685 }