Convert some plugins to new logger
[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 #include "olsr_logging.h"
54
55 #include <net/route.h>
56 #include <arpa/inet.h>
57 #ifdef linux
58 #include <linux/in_route.h>
59 #endif
60 #ifndef WIN32
61 #include <pthread.h>
62 #else
63 #define WIN32_LEAN_AND_MEAN
64 #include <windows.h>
65 #undef interface
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   uint8_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                                 uint8_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 *, uint8_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_WARN(LOG_PLUGINS, "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,"%127s %127s", s_netaddr, s_mask);
160     if (i != 2) {
161         OLSR_WARN(LOG_PLUGINS, "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_WARN(LOG_PLUGINS, "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_WARN(LOG_PLUGINS, "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, olsr_cnf->ip_version)) {
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, uint8_t prefixlen, struct ping_list *the_ping_list)
306 {
307     char buf[1024], iface[16];
308     uint32_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         OLSR_WARN(LOG_PLUGINS, "Cannot read proc file %s: %s\n", PROCENTRY_ROUTE, strerror(errno));
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_DEBUG(LOG_PLUGINS, "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_DEBUG(LOG_PLUGINS, "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_WARN(LOG_PLUGINS, "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     if (system(ping_command) == 0) {
384       OLSR_DEBUG(LOG_PLUGINS, "\nDo ping on %s ... ok\n", list->ping_address);
385       return 1;
386     }
387     OLSR_DEBUG(LOG_PLUGINS, "\nDo ping on %s ... failed\n", list->ping_address);
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 = olsr_malloc(sizeof(struct ping_list), "ping list");
397   new->ping_address = olsr_strdup(ping_address);
398   new->next = the_ping_list;
399   return new;
400 }
401
402
403
404 static struct hna_list *
405 add_to_hna_list(struct hna_list * list_root, union olsr_ip_addr *hna_net, uint8_t hna_prefixlen )
406 {
407   struct hna_list *new = olsr_malloc(sizeof(struct hna_list), "hna list");
408   //memcpy(&new->hna_net,hna_net,sizeof(union hna_net));
409   //memcpy(&new->hna_netmask,hna_netmask,sizeof(union hna_netmask));
410   new->hna_net.v4=hna_net->v4;
411   new->hna_prefixlen=hna_prefixlen;
412   new->hna_added=0;
413   new->probe_ok=0;
414   new->ping_hosts=NULL;
415   new->next=list_root;
416   return new;
417 }
418
419 #ifdef WIN32
420 /*
421  * Windows ptread compat stuff
422  */
423 static unsigned long __stdcall ThreadWrapper(void *Para)
424 {
425   struct ThreadPara *Cast;
426   void *(*Func)(void *);
427   void *Arg;
428
429   Cast = (struct ThreadPara *)Para;
430
431   Func = Cast->Func;
432   Arg = Cast->Arg;
433
434   HeapFree(GetProcessHeap(), 0, Para);
435
436   Func(Arg);
437
438   return 0;
439 }
440
441 int pthread_create(HANDLE *Hand, void *Attr __attribute__((unused)), void *(*Func)(void *), void *Arg)
442 {
443   struct ThreadPara *Para;
444   unsigned long ThreadId;
445
446   Para = HeapAlloc(GetProcessHeap(), 0, sizeof (struct ThreadPara));
447
448   if (Para == NULL)
449     return -1;
450
451   Para->Func = Func;
452   Para->Arg = Arg;
453
454   *Hand = CreateThread(NULL, 0, ThreadWrapper, Para, 0, &ThreadId);
455
456   if (*Hand == NULL)
457     return -1;
458
459   return 0;
460 }
461
462 int pthread_kill(HANDLE Hand, int Sig __attribute__((unused)))
463 {
464   if (!TerminateThread(Hand, 0))
465     return -1;
466
467   return 0;
468 }
469
470 int pthread_mutex_init(HANDLE *Hand, void *Attr __attribute__((unused)))
471 {
472   *Hand = CreateMutex(NULL, FALSE, NULL);
473
474   if (*Hand == NULL)
475     return -1;
476
477   return 0;
478 }
479
480 int pthread_mutex_lock(HANDLE *Hand)
481 {
482   if (WaitForSingleObject(*Hand, INFINITE) == WAIT_FAILED)
483     return -1;
484
485   return 0;
486 }
487
488 int pthread_mutex_unlock(HANDLE *Hand)
489 {
490   if (!ReleaseMutex(*Hand))
491     return -1;
492
493   return 0;
494 }
495
496 #endif
497
498 /*
499  * Local Variables:
500  * c-basic-offset: 2
501  * indent-tabs-mode: nil
502  * End:
503  */