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