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