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