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