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