3c2e53f2ff174383ddc72c4c3cbc637cb7f3c22d
[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     char *endptr;
139     const double d = strtod(value, &endptr);
140     if (*endptr != '\0' || endptr == value) {
141         OLSR_PRINTF(0, "Illegal double \"%s\"", value);
142         return 1;
143     }
144     if (data != NULL) {
145         double *v = data;
146         *v = d;
147         OLSR_PRINTF(1, "%s double %lf\n", "Got", d);
148     } else {
149         OLSR_PRINTF(0, "%s double %lf\n", "Ignored", d);
150     }
151     return 0;
152 }
153
154 static int set_plugin_ping(const char *value, void *data __attribute__((unused)), set_plugin_parameter_addon addon __attribute__((unused)))
155 {
156     union olsr_ip_addr foo_addr;
157
158     if (inet_pton(olsr_cnf->ip_version, value, &foo_addr) <= 0) {
159         OLSR_PRINTF(0, "Illegal IP address \"%s\"", value);
160         return 1;
161     }
162     /*if first ping without hna then assume inet gateway*/
163     if (the_hna_list == NULL){
164         union olsr_ip_addr temp_net;
165         union olsr_ip_addr temp_netmask;
166         temp_net.v4.s_addr = INET_NET;
167         temp_netmask.v4.s_addr = INET_PREFIX;
168         the_hna_list = add_to_hna_list(the_hna_list, &temp_net, olsr_netmask_to_prefix(&temp_netmask));
169         if (the_hna_list == NULL) {
170             return 1;
171         }
172     }
173     the_hna_list->ping_hosts = add_to_ping_list(value, the_hna_list->ping_hosts);
174     return 0;
175 }
176
177 static int set_plugin_hna(const char *value, void *data __attribute__((unused)), set_plugin_parameter_addon addon __attribute__((unused)))
178 {
179     union olsr_ip_addr temp_net;
180     union olsr_ip_addr temp_netmask;
181     char s_netaddr[128];
182     char s_mask[128];
183
184     //192.168.1.0  255.255.255.0
185     int i = sscanf(value,"%128s %128s", s_netaddr, s_mask);
186     if (i != 2) {
187         OLSR_PRINTF(0, "Cannot get IP address and netmask from \"%s\"", value);
188         return 1;
189     }
190
191     //printf("%s():i:%i; net:%s; mask:%s\n",__func__,i,s_netaddr,s_mask);
192     if (inet_pton(olsr_cnf->ip_version, s_netaddr, &temp_net) <= 0) {
193         OLSR_PRINTF(0, "Illegal IP address \"%s\"", s_netaddr);
194         return 1;
195     }
196
197     //printf("GOT: %s(%08x)",inet_ntoa(foo_addr),foo_addr.s_addr);
198     if (inet_pton(olsr_cnf->ip_version, s_netaddr, &temp_netmask) <= 0) {
199         OLSR_PRINTF(0, "Illegal netmask \"%s\"", s_netaddr);
200         return 1;
201     }
202
203     //printf("/%s(%08x)\n",inet_ntoa(foo_addr),foo_addr.s_addr);
204     //printf("%s():got->%s/%s\n",__func__,olsr_ip_to_string((union olsr_ip_addr *)&));
205     the_hna_list = add_to_hna_list(the_hna_list, &temp_net, olsr_netmask_to_prefix(&temp_netmask));
206     if (the_hna_list != NULL) {
207         return 1;
208     }
209     return 0;
210 }
211
212 static const struct olsrd_plugin_parameters plugin_parameters[] = {
213     { .name = "interval", .set_plugin_parameter = &set_plugin_double, .data = &check_interval },
214     { .name = "ping",     .set_plugin_parameter = &set_plugin_ping,   .data = NULL },
215     { .name = "hna",      .set_plugin_parameter = &set_plugin_hna,    .data = NULL },
216 };
217
218 void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
219 {
220     *params = plugin_parameters;
221     *size = sizeof(plugin_parameters)/sizeof(*plugin_parameters);
222 }
223
224 /**
225  *Do initialization here
226  * 
227  *
228  *This function is called by the my_init
229  *function in uolsrd_plugin.c
230  *It is ran _after_ register_olsr_param
231  */
232 int
233 olsrd_plugin_init(void)
234 {
235   pthread_t ping_thread;
236   
237   //gw_net.v4 = INET_NET;
238   //gw_netmask.v4 = INET_PREFIX;
239
240   //gw_already_added = 0;
241   //has_available_gw = 0;
242
243   
244   /* Remove all local Inet HNA entries */
245   /*while(remove_local_hna4_entry(&gw_net, &gw_netmask))
246   {
247     olsr_printf(1, "HNA Internet gateway deleted\n");
248   }*/
249
250   pthread_create(&ping_thread, NULL, (void *(*)(void *))looped_checks, NULL);
251   
252   /* Register the GW check */
253   olsr_start_timer(3 * MSEC_PER_SEC, 0, OLSR_TIMER_PERIODIC,
254                    &olsr_event_doing_hna, NULL, 0);
255
256   return 1;
257 }
258
259
260 /**
261  * Scheduled event to update the hna table,
262  * called from olsrd main thread to keep the hna table thread-safe
263  */
264 static void
265 olsr_event_doing_hna(void *foo __attribute__((unused)))
266 {
267         struct hna_list *li;
268         /*
269   if (has_available_gw == 1 && gw_already_added == 0) {
270     olsr_printf(1, "Adding OLSR local HNA entry for Internet\n");
271     add_local_hna_entry(&gw_net, &gw_netmask);
272     gw_already_added = 1;
273   } else if ((has_available_gw == 0) && (gw_already_added == 1)) {
274     // Remove all local Inet HNA entries /
275     while(remove_local_hna4_entry(&gw_net, &gw_netmask)) {
276       olsr_printf(1, "Removing OLSR local HNA entry for Internet\n");
277     }
278     gw_already_added = 0;
279   }
280         */
281         for(li=the_hna_list; li; li=li->next){
282                 if((li->probe_ok==1)&&(li->hna_added==0)){
283                         olsr_printf(1, "Adding OLSR local HNA entry\n");
284                         ip_prefix_list_add(&olsr_cnf->hna_entries, &li->hna_net, li->hna_prefixlen);
285                         li->hna_added=1;
286                 }else if((li->probe_ok==0)&&(li->hna_added==1)){
287                         while(ip_prefix_list_remove(&olsr_cnf->hna_entries, &li->hna_net, li->hna_prefixlen)) {
288                                 olsr_printf(1, "Removing OLSR local HNA entry\n");
289                         }
290                         li->hna_added=0;
291                 }
292         }
293 }
294
295
296
297 /**
298  * the threaded function which happens within an endless loop,
299  * reiterated every "Interval" sec (as given in the config or 
300  * the default value)
301  */
302 static void
303 looped_checks(void *foo __attribute__((unused)))
304 {
305   for(;;) {
306     struct hna_list *li;
307     struct timespec remainder_spec;
308     /* the time to wait in "Interval" sec (see connfig), default=5sec */
309     struct timespec sleeptime_spec  = { check_interval, 0L };
310
311     for(li = the_hna_list; li; li = li->next){
312       /* check for gw in table entry and if Ping IPs are given also do pings */
313       li->probe_ok = check_gw(&li->hna_net,li->hna_prefixlen,li->ping_hosts);
314       //has_available_gw = check_gw(&gw_net, &gw_netmask);
315     }
316
317     while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
318       sleeptime_spec = remainder_spec;
319   }
320   // return NULL;
321 }
322
323
324
325 static int
326 check_gw(union olsr_ip_addr *net, olsr_u8_t prefixlen, struct ping_list *the_ping_list)
327 {
328     char buf[1024], iface[16];
329     olsr_u32_t gate_addr, dest_addr, netmask;
330     unsigned int iflags;
331     int metric, refcnt, use;
332     int retval = 0;
333     union olsr_ip_addr mask;
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     olsr_prefix_to_netmask(&mask, prefixlen);
344     /*
345     olsr_printf(1, "Genmask         Destination     Gateway         "
346                 "Flags Metric Ref    Use Iface\n");
347     */
348     while (fgets(buf, sizeof(buf), fp))
349       { 
350         int num = sscanf(buf, "%15s %128X %128X %X %d %d %d %128X \n",
351                          iface, &dest_addr, &gate_addr,
352                          &iflags, &refcnt, &use, &metric, &netmask);
353         if (num < 8)
354             continue;
355
356         /*
357         olsr_printf(1, "%-15s ", olsr_ip_to_string((union olsr_ip_addr *)&netmask));
358
359         olsr_printf(1, "%-15s ", olsr_ip_to_string((union olsr_ip_addr *)&dest_addr));
360
361         olsr_printf(1, "%-15s %-6d %-2d %7d %s\n",
362                     olsr_ip_to_string((union olsr_ip_addr *)&gate_addr),
363                     metric, refcnt, use, iface);
364         */
365
366         if( (iflags & RTF_UP) &&
367             (metric == 0) &&
368             (netmask == mask.v4.s_addr) && 
369             (dest_addr == net->v4.s_addr))
370           {
371             if ( ((mask.v4.s_addr == INET_PREFIX)&&(net->v4.s_addr == INET_NET))&&(!(iflags & RTF_GATEWAY)))
372               {
373                 fclose(fp);  
374                 return retval;
375               }
376             /* don't ping, if there was no "Ping" IP addr in the config file */
377             if (the_ping_list != NULL) {  
378               /*validate the found inet gw by pinging*/ 
379               if (ping_is_possible(the_ping_list)) {
380                 olsr_printf(1, "HNA[%08x/%08x](ping is possible) VIA %s detected in routing table.\n", dest_addr,netmask,iface);
381                 retval=1;      
382               }
383             } else {
384               olsr_printf(1, "HNA[%08x/%08x] VIA %s detected in routing table.\n", dest_addr,netmask,iface);
385               retval=1;      
386             }
387           }
388       }
389
390     fclose(fp);      
391     if(retval == 0){
392       /* And we cast here since we get warnings on Win32 */
393       olsr_printf(1, "HNA[%08x/%08x] is invalid\n", (unsigned int)net->v4.s_addr, (unsigned int)mask.v4.s_addr);
394     }  
395     return retval;
396 }
397
398 static int
399 ping_is_possible(struct ping_list *the_ping_list) 
400 {
401   struct ping_list *list;
402   for(list = the_ping_list; list; list = list->next) {
403     char ping_command[50];
404     snprintf(ping_command, sizeof(ping_command), "ping -c 1 -q %s", list->ping_address);
405     olsr_printf(1, "\nDo ping on %s ...\n", list->ping_address);
406     if (system(ping_command) == 0) {
407       olsr_printf(1, "...OK\n\n");
408       return 1;      
409     }
410     olsr_printf(1, "...FAILED\n\n");
411   }
412   return 0;
413 }
414
415 /* add the valid IPs to the head of the list */
416 static struct ping_list *
417 add_to_ping_list(const char *ping_address, struct ping_list *the_ping_list)
418 {
419   struct ping_list *new = malloc(sizeof(struct ping_list));
420   if(!new)
421   {
422     fprintf(stderr, "DYN GW: Out of memory!\n");
423     exit(0);
424   }
425   new->ping_address = strdup(ping_address);
426   new->next = the_ping_list;
427   return new;
428 }    
429
430
431
432 static struct hna_list *
433 add_to_hna_list(struct hna_list * list_root, union olsr_ip_addr *hna_net, olsr_u8_t hna_prefixlen )
434 {
435   struct hna_list *new = malloc(sizeof(struct hna_list));
436   if(new == NULL)
437   {
438     fprintf(stderr, "DYN GW: Out of memory!\n");
439     exit(0);
440   }
441   //memcpy(&new->hna_net,hna_net,sizeof(union hna_net));
442   //memcpy(&new->hna_netmask,hna_netmask,sizeof(union hna_netmask));
443   new->hna_net.v4=hna_net->v4;
444   new->hna_prefixlen=hna_prefixlen;
445   new->hna_added=0;
446   new->probe_ok=0;
447   new->ping_hosts=NULL;
448   new->next=list_root;  
449   return new;
450 }
451
452 #ifdef WIN32
453 /*
454  * Windows ptread compat stuff
455  */
456 static unsigned long __stdcall ThreadWrapper(void *Para)
457 {
458   struct ThreadPara *Cast;
459   void *(*Func)(void *);
460   void *Arg;
461
462   Cast = (struct ThreadPara *)Para;
463
464   Func = Cast->Func;
465   Arg = Cast->Arg;
466   
467   HeapFree(GetProcessHeap(), 0, Para);
468
469   Func(Arg);
470
471   return 0;
472 }
473
474 int pthread_create(HANDLE *Hand, void *Attr __attribute__((unused)), void *(*Func)(void *), void *Arg)
475 {
476   struct ThreadPara *Para;
477   unsigned long ThreadId;
478
479   Para = HeapAlloc(GetProcessHeap(), 0, sizeof (struct ThreadPara));
480
481   if (Para == NULL)
482     return -1;
483
484   Para->Func = Func;
485   Para->Arg = Arg;
486
487   *Hand = CreateThread(NULL, 0, ThreadWrapper, Para, 0, &ThreadId);
488
489   if (*Hand == NULL)
490     return -1;
491
492   return 0;
493 }
494
495 int pthread_kill(HANDLE Hand, int Sig __attribute__((unused)))
496 {
497   if (!TerminateThread(Hand, 0))
498     return -1;
499
500   return 0;
501 }
502
503 int pthread_mutex_init(HANDLE *Hand, void *Attr __attribute__((unused)))
504 {
505   *Hand = CreateMutex(NULL, FALSE, NULL);
506
507   if (*Hand == NULL)
508     return -1;
509
510   return 0;
511 }
512
513 int pthread_mutex_lock(HANDLE *Hand)
514 {
515   if (WaitForSingleObject(*Hand, INFINITE) == WAIT_FAILED)
516     return -1;
517
518   return 0;
519 }
520
521 int pthread_mutex_unlock(HANDLE *Hand)
522 {
523   if (!ReleaseMutex(*Hand))
524     return -1;
525
526   return 0;
527 }
528
529 #endif