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