* converted to plugin interface version 5
[olsrd.git] / lib / dyn_gw / src / olsrd_dyn_gw.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas T√łnnesen(andreto@olsr.org)
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  * $Id: olsrd_dyn_gw.c,v 1.22 2007/09/13 15:41:12 bernd67 Exp $
41  */
42
43 /*
44  * -Threaded ping code added by Jens Nachitgall
45  * -HNA4 checking by bjoern riemer
46  */
47
48 #include <arpa/inet.h>
49
50 #include "olsr_types.h"
51 #include "olsrd_dyn_gw.h"
52 #include "scheduler.h"
53 #include "olsr.h"
54 #include "local_hna_set.h"
55 #include "defs.h"
56
57 #include <stdio.h>
58 #include <string.h>
59 #include <stdlib.h>
60 #include <sys/time.h>
61 #include <net/route.h>
62 #ifdef linux
63 #include <linux/in_route.h>
64 #endif
65 #include <unistd.h>
66 #include <errno.h>
67 #include <time.h>
68 #ifndef WIN32
69 #include <pthread.h>
70 #else
71 #define WIN32_LEAN_AND_MEAN
72 #include <windows.h>
73 #undef interface
74
75 #define close(x) closesocket(x)
76
77 typedef HANDLE pthread_mutex_t;
78 typedef HANDLE pthread_t;
79
80 int pthread_create(HANDLE *Hand, void *Attr, void *(*Func)(void *), void *Arg);
81 int pthread_kill(HANDLE Hand, int Sig);
82 int pthread_mutex_init(HANDLE *Hand, void *Attr);
83 int pthread_mutex_lock(HANDLE *Hand);
84 int pthread_mutex_unlock(HANDLE *Hand);
85
86 struct ThreadPara
87 {
88   void *(*Func)(void *);
89   void *Arg;
90 };
91 #endif
92
93
94 /* set default interval, in case none is given in the config file */
95 static int check_interval = 5;
96
97 /* list to store the Ping IP addresses given in the config file */
98 struct ping_list {
99   char *ping_address;
100   struct ping_list *next;
101 };
102
103 static struct ping_list *
104 add_to_ping_list(const char *, struct ping_list *);
105
106 struct hna_list {
107   union olsr_ip_addr hna_net;
108   union olsr_ip_addr hna_netmask;
109   struct ping_list *ping_hosts;
110   int hna_added;
111   int probe_ok;
112   struct hna_list *next;
113 };
114
115 static struct hna_list *
116         add_to_hna_list(struct hna_list *,
117                                 union olsr_ip_addr *hna_net,
118                                 union olsr_ip_addr *hna_netmask );
119
120 struct hna_list *the_hna_list = NULL;
121
122 static void
123 looped_checks(void *) __attribute__((noreturn));
124
125 static int
126 check_gw(union olsr_ip_addr *, union olsr_ip_addr *,struct ping_list *);
127
128 static int
129 ping_is_possible(struct ping_list *);
130
131 /* Event function to register with the scheduler */
132 static void
133 olsr_event_doing_hna(void *);
134
135 /**
136  * read config file parameters
137  */
138 static int set_plugin_double(const char *value, void *data, unsigned int addon __attribute__((unused)))
139 {
140     char *endptr;
141     const double d = strtod(value, &endptr);
142     if (*endptr != '\0' || endptr == value) {
143         OLSR_PRINTF(0, "Illegal double \"%s\"", value);
144         return 1;
145     }
146     if (data != NULL) {
147         double *v = data;
148         *v = d;
149         OLSR_PRINTF(1, "%s double %lf\n", "Got", d);
150     } else {
151         OLSR_PRINTF(0, "%s double %lf\n", "Ignored", d);
152     }
153     return 0;
154 }
155
156 static int set_plugin_ping(const char *value, void *data __attribute__((unused)), unsigned int addon __attribute__((unused)))
157 {
158     union olsr_ip_addr foo_addr;
159
160     if (inet_pton(olsr_cnf->ip_version, value, &foo_addr) <= 0) {
161         OLSR_PRINTF(0, "Illegal IP address \"%s\"", value);
162         return 1;
163     }
164     /*if first ping without hna then assume inet gateway*/
165     if (the_hna_list == NULL){
166         union olsr_ip_addr temp_net;
167         union olsr_ip_addr temp_netmask;
168         temp_net.v4 = INET_NET;
169         temp_netmask.v4 = INET_PREFIX;
170         the_hna_list = add_to_hna_list(the_hna_list, &temp_net, &temp_netmask);
171         if (the_hna_list == NULL) {
172             return 1;
173         }
174     }
175     the_hna_list->ping_hosts = add_to_ping_list(value, the_hna_list->ping_hosts);
176     return 0;
177 }
178
179 static int set_plugin_hna(const char *value, void *data __attribute__((unused)), unsigned int addon __attribute__((unused)))
180 {
181     union olsr_ip_addr temp_net;
182     union olsr_ip_addr temp_netmask;
183     char s_netaddr[128];
184     char s_mask[128];
185
186     //192.168.1.0  255.255.255.0
187     int i = sscanf(value,"%128s %128s", s_netaddr, s_mask);
188     if (i != 2) {
189         OLSR_PRINTF(0, "Cannot get IP address and netmask from \"%s\"", value);
190         return 1;
191     }
192
193     //printf("%s():i:%i; net:%s; mask:%s\n",__func__,i,s_netaddr,s_mask);
194     if (inet_pton(olsr_cnf->ip_version, s_netaddr, &temp_net) <= 0) {
195         OLSR_PRINTF(0, "Illegal IP address \"%s\"", s_netaddr);
196         return 1;
197     }
198
199     //printf("GOT: %s(%08x)",inet_ntoa(foo_addr),foo_addr.s_addr);
200     if (inet_pton(olsr_cnf->ip_version, s_netaddr, &temp_netmask) <= 0) {
201         OLSR_PRINTF(0, "Illegal netmask \"%s\"", s_netaddr);
202         return 1;
203     }
204
205     //printf("/%s(%08x)\n",inet_ntoa(foo_addr),foo_addr.s_addr);
206     //printf("%s():got->%s/%s\n",__func__,olsr_ip_to_string((union olsr_ip_addr *)&));
207     the_hna_list = add_to_hna_list(the_hna_list, &temp_net, &temp_netmask);
208     if (the_hna_list != NULL) {
209         return 1;
210     }
211     return 0;
212 }
213
214 static const struct olsrd_plugin_parameters plugin_parameters[] = {
215     { .name = "interval", .set_plugin_parameter = &set_plugin_double, .data = &check_interval },
216     { .name = "ping",     .set_plugin_parameter = &set_plugin_ping,   .data = NULL },
217     { .name = "hna",      .set_plugin_parameter = &set_plugin_hna,    .data = NULL },
218 };
219
220 void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
221 {
222     *params = plugin_parameters;
223     *size = sizeof(plugin_parameters)/sizeof(*plugin_parameters);
224 }
225
226 /**
227  *Do initialization here
228  * 
229  *
230  *This function is called by the my_init
231  *function in uolsrd_plugin.c
232  *It is ran _after_ register_olsr_param
233  */
234 int
235 olsrd_plugin_init(void)
236 {
237   pthread_t ping_thread;
238   
239   //gw_net.v4 = INET_NET;
240   //gw_netmask.v4 = INET_PREFIX;
241
242   //gw_already_added = 0;
243   //has_available_gw = 0;
244
245   
246   /* Remove all local Inet HNA entries */
247   /*while(remove_local_hna4_entry(&gw_net, &gw_netmask))
248   {
249     olsr_printf(1, "HNA Internet gateway deleted\n");
250   }*/
251
252   pthread_create(&ping_thread, NULL, (void *(*)(void *))looped_checks, NULL);
253   
254   /* Register the GW check */
255   olsr_register_scheduler_event(&olsr_event_doing_hna, NULL, 3, 4, NULL);
256
257   return 1;
258 }
259
260
261 /**
262  * Scheduled event to update the hna table,
263  * called from olsrd main thread to keep the hna table thread-safe
264  */
265 static void
266 olsr_event_doing_hna(void *foo __attribute__((unused)))
267 {
268         struct hna_list *li;
269         /*
270   if (has_available_gw == 1 && gw_already_added == 0) {
271     olsr_printf(1, "Adding OLSR local HNA entry for Internet\n");
272     add_local_hna4_entry(&gw_net, &gw_netmask);
273     gw_already_added = 1;
274   } else if ((has_available_gw == 0) && (gw_already_added == 1)) {
275     // Remove all local Inet HNA entries /
276     while(remove_local_hna4_entry(&gw_net, &gw_netmask)) {
277       olsr_printf(1, "Removing OLSR local HNA entry for Internet\n");
278     }
279     gw_already_added = 0;
280   }
281         */
282         for(li=the_hna_list; li; li=li->next){
283                 if((li->probe_ok==1)&&(li->hna_added==0)){
284                         olsr_printf(1, "Adding OLSR local HNA entry\n");
285                         add_local_hna4_entry(&li->hna_net, &li->hna_netmask);
286                         li->hna_added=1;
287                 }else if((li->probe_ok==0)&&(li->hna_added==1)){
288                         while(remove_local_hna4_entry(&li->hna_net, &li->hna_netmask)) {
289                                 olsr_printf(1, "Removing OLSR local HNA entry\n");
290                         }
291                         li->hna_added=0;
292                 }
293         }
294 }
295
296
297
298 /**
299  * the threaded function which happens within an endless loop,
300  * reiterated every "Interval" sec (as given in the config or 
301  * the default value)
302  */
303 static void
304 looped_checks(void *foo __attribute__((unused)))
305 {
306   for(;;) {
307     struct hna_list *li;
308     struct timespec remainder_spec;
309     /* the time to wait in "Interval" sec (see connfig), default=5sec */
310     struct timespec sleeptime_spec  = { check_interval, 0L };
311
312     for(li = the_hna_list; li; li = li->next){
313       /* check for gw in table entry and if Ping IPs are given also do pings */
314       li->probe_ok = check_gw(&li->hna_net,&li->hna_netmask,li->ping_hosts);
315       //has_available_gw = check_gw(&gw_net, &gw_netmask);
316     }
317
318     while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
319       sleeptime_spec = remainder_spec;
320   }
321   // return NULL;
322 }
323
324
325
326 static int
327 check_gw(union olsr_ip_addr *net, union olsr_ip_addr *mask, struct ping_list *the_ping_list)
328 {
329     char buf[1024], iface[16];
330     olsr_u32_t gate_addr, dest_addr, netmask;
331     unsigned int iflags;
332     int metric, refcnt, use;
333     int retval = 0;
334
335     FILE *fp = fopen(PROCENTRY_ROUTE, "r");
336     if (!fp) 
337       {
338         perror(PROCENTRY_ROUTE);
339         olsr_printf(1, "INET (IPv4) not configured in this system.\n");
340         return -1;
341       }    
342
343     /*
344     olsr_printf(1, "Genmask         Destination     Gateway         "
345                 "Flags Metric Ref    Use Iface\n");
346     */
347     while (fgets(buf, sizeof(buf), fp))
348       { 
349         int num = sscanf(buf, "%15s %128X %128X %X %d %d %d %128X \n",
350                          iface, &dest_addr, &gate_addr,
351                          &iflags, &refcnt, &use, &metric, &netmask);
352         if (num < 8)
353             continue;
354
355         /*
356         olsr_printf(1, "%-15s ", olsr_ip_to_string((union olsr_ip_addr *)&netmask));
357
358         olsr_printf(1, "%-15s ", olsr_ip_to_string((union olsr_ip_addr *)&dest_addr));
359
360         olsr_printf(1, "%-15s %-6d %-2d %7d %s\n",
361                     olsr_ip_to_string((union olsr_ip_addr *)&gate_addr),
362                     metric, refcnt, use, iface);
363         */
364
365         if( (iflags & RTF_UP) &&
366             (metric == 0) &&
367             (netmask == mask->v4) && 
368             (dest_addr == net->v4))
369           {
370             if ( ((mask->v4==INET_PREFIX)&&(net->v4==INET_NET))&&(!(iflags & RTF_GATEWAY)))
371               {
372                 fclose(fp);  
373                 return retval;
374               }
375             /* don't ping, if there was no "Ping" IP addr in the config file */
376             if (the_ping_list != NULL) {  
377               /*validate the found inet gw by pinging*/ 
378               if (ping_is_possible(the_ping_list)) {
379                 olsr_printf(1, "HNA[%08x/%08x](ping is possible) VIA %s detected in routing table.\n", dest_addr,netmask,iface);
380                 retval=1;      
381               }
382             } else {
383               olsr_printf(1, "HNA[%08x/%08x] VIA %s detected in routing table.\n", dest_addr,netmask,iface);
384               retval=1;      
385             }
386           }
387       }
388
389     fclose(fp);      
390     if(retval == 0){
391       olsr_printf(1, "HNA[%08x/%08x] is invalid\n", net->v4,mask->v4);
392     }  
393     return retval;
394 }
395
396 static int
397 ping_is_possible(struct ping_list *the_ping_list) 
398 {
399   struct ping_list *list;
400   for(list = the_ping_list; list; list = list->next) {
401     char ping_command[50];
402     snprintf(ping_command, sizeof(ping_command), "ping -c 1 -q %s", list->ping_address);
403     olsr_printf(1, "\nDo ping on %s ...\n", list->ping_address);
404     if (system(ping_command) == 0) {
405       olsr_printf(1, "...OK\n\n");
406       return 1;      
407     }
408     olsr_printf(1, "...FAILED\n\n");
409   }
410   return 0;
411 }
412
413 /* add the valid IPs to the head of the list */
414 static struct ping_list *
415 add_to_ping_list(const char *ping_address, struct ping_list *the_ping_list)
416 {
417   struct ping_list *new = malloc(sizeof(struct ping_list));
418   if(!new)
419   {
420     fprintf(stderr, "DYN GW: Out of memory!\n");
421     exit(0);
422   }
423   new->ping_address = strdup(ping_address);
424   new->next = the_ping_list;
425   return new;
426 }    
427
428
429
430 static struct hna_list *
431 add_to_hna_list(struct hna_list * list_root, union olsr_ip_addr *hna_net, union olsr_ip_addr *hna_netmask )
432 {
433   struct hna_list *new = malloc(sizeof(struct hna_list));
434   if(new == NULL)
435   {
436     fprintf(stderr, "DYN GW: Out of memory!\n");
437     exit(0);
438   }
439   //memcpy(&new->hna_net,hna_net,sizeof(union hna_net));
440   //memcpy(&new->hna_netmask,hna_netmask,sizeof(union hna_netmask));
441   new->hna_net.v4=hna_net->v4;
442   new->hna_netmask.v4=hna_netmask->v4;
443   new->hna_added=0;
444   new->probe_ok=0;
445   new->ping_hosts=NULL;
446   new->next=list_root;  
447   return new;
448 }
449
450 #ifdef WIN32
451 /*
452  * Windows ptread compat stuff
453  */
454 static unsigned long __stdcall ThreadWrapper(void *Para)
455 {
456   struct ThreadPara *Cast;
457   void *(*Func)(void *);
458   void *Arg;
459
460   Cast = (struct ThreadPara *)Para;
461
462   Func = Cast->Func;
463   Arg = Cast->Arg;
464   
465   HeapFree(GetProcessHeap(), 0, Para);
466
467   Func(Arg);
468
469   return 0;
470 }
471
472 int pthread_create(HANDLE *Hand, void *Attr __attribute__((unused)), void *(*Func)(void *), void *Arg)
473 {
474   struct ThreadPara *Para;
475   unsigned long ThreadId;
476
477   Para = HeapAlloc(GetProcessHeap(), 0, sizeof (struct ThreadPara));
478
479   if (Para == NULL)
480     return -1;
481
482   Para->Func = Func;
483   Para->Arg = Arg;
484
485   *Hand = CreateThread(NULL, 0, ThreadWrapper, Para, 0, &ThreadId);
486
487   if (*Hand == NULL)
488     return -1;
489
490   return 0;
491 }
492
493 int pthread_kill(HANDLE Hand, int Sig __attribute__((unused)))
494 {
495   if (!TerminateThread(Hand, 0))
496     return -1;
497
498   return 0;
499 }
500
501 int pthread_mutex_init(HANDLE *Hand, void *Attr __attribute__((unused)))
502 {
503   *Hand = CreateMutex(NULL, FALSE, NULL);
504
505   if (*Hand == NULL)
506     return -1;
507
508   return 0;
509 }
510
511 int pthread_mutex_lock(HANDLE *Hand)
512 {
513   if (WaitForSingleObject(*Hand, INFINITE) == WAIT_FAILED)
514     return -1;
515
516   return 0;
517 }
518
519 int pthread_mutex_unlock(HANDLE *Hand)
520 {
521   if (!ReleaseMutex(*Hand))
522     return -1;
523
524   return 0;
525 }
526
527 #endif