/*
* The olsr.org Optimized Link-State Routing daemon(olsrd)
* Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of olsr.org, olsrd nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Visit http://www.olsr.org for more information.
*
* If you find this software useful feel free to make a donation
* to the project. For more information see the website or contact
* the copyright holders.
*
* $Id: olsrd_dyn_gw.c,v 1.23 2007/09/17 21:57:05 bernd67 Exp $
*/
/*
* -Threaded ping code added by Jens Nachitgall
* -HNA4 checking by bjoern riemer
*/
#include <arpa/inet.h>
#include "olsr_types.h"
#include "olsrd_dyn_gw.h"
#include "scheduler.h"
#include "olsr.h"
#include "local_hna_set.h"
#include "defs.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <net/route.h>
#ifdef linux
#include <linux/in_route.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <time.h>
#ifndef WIN32
#include <pthread.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef interface
#define close(x) closesocket(x)
typedef HANDLE pthread_mutex_t;
typedef HANDLE pthread_t;
int pthread_create(HANDLE *Hand, void *Attr, void *(*Func)(void *), void *Arg);
int pthread_kill(HANDLE Hand, int Sig);
int pthread_mutex_init(HANDLE *Hand, void *Attr);
int pthread_mutex_lock(HANDLE *Hand);
int pthread_mutex_unlock(HANDLE *Hand);
struct ThreadPara
{
void *(*Func)(void *);
void *Arg;
};
#endif
/* set default interval, in case none is given in the config file */
static int check_interval = 5;
/* list to store the Ping IP addresses given in the config file */
struct ping_list {
char *ping_address;
struct ping_list *next;
};
static struct ping_list *
add_to_ping_list(const char *, struct ping_list *);
struct hna_list {
union olsr_ip_addr hna_net;
union olsr_ip_addr hna_netmask;
struct ping_list *ping_hosts;
int hna_added;
int probe_ok;
struct hna_list *next;
};
static struct hna_list *
add_to_hna_list(struct hna_list *,
union olsr_ip_addr *hna_net,
union olsr_ip_addr *hna_netmask );
struct hna_list *the_hna_list = NULL;
static void
looped_checks(void *) __attribute__((noreturn));
static int
check_gw(union olsr_ip_addr *, union olsr_ip_addr *,struct ping_list *);
static int
ping_is_possible(struct ping_list *);
/* Event function to register with the scheduler */
static void
olsr_event_doing_hna(void *);
/**
* read config file parameters
*/
static int set_plugin_double(const char *value, void *data, set_plugin_parameter_addon addon __attribute__((unused)))
{
char *endptr;
const double d = strtod(value, &endptr);
if (*endptr != '\0' || endptr == value) {
OLSR_PRINTF(0, "Illegal double \"%s\"", value);
return 1;
}
if (data != NULL) {
double *v = data;
*v = d;
OLSR_PRINTF(1, "%s double %lf\n", "Got", d);
} else {
OLSR_PRINTF(0, "%s double %lf\n", "Ignored", d);
}
return 0;
}
static int set_plugin_ping(const char *value, void *data __attribute__((unused)), set_plugin_parameter_addon addon __attribute__((unused)))
{
union olsr_ip_addr foo_addr;
if (inet_pton(olsr_cnf->ip_version, value, &foo_addr) <= 0) {
OLSR_PRINTF(0, "Illegal IP address \"%s\"", value);
return 1;
}
/*if first ping without hna then assume inet gateway*/
if (the_hna_list == NULL){
union olsr_ip_addr temp_net;
union olsr_ip_addr temp_netmask;
temp_net.v4 = INET_NET;
temp_netmask.v4 = INET_PREFIX;
the_hna_list = add_to_hna_list(the_hna_list, &temp_net, &temp_netmask);
if (the_hna_list == NULL) {
return 1;
}
}
the_hna_list->ping_hosts = add_to_ping_list(value, the_hna_list->ping_hosts);
return 0;
}
static int set_plugin_hna(const char *value, void *data __attribute__((unused)), set_plugin_parameter_addon addon __attribute__((unused)))
{
union olsr_ip_addr temp_net;
union olsr_ip_addr temp_netmask;
char s_netaddr[128];
char s_mask[128];
//192.168.1.0 255.255.255.0
int i = sscanf(value,"%128s %128s", s_netaddr, s_mask);
if (i != 2) {
OLSR_PRINTF(0, "Cannot get IP address and netmask from \"%s\"", value);
return 1;
}
//printf("%s():i:%i; net:%s; mask:%s\n",__func__,i,s_netaddr,s_mask);
if (inet_pton(olsr_cnf->ip_version, s_netaddr, &temp_net) <= 0) {
OLSR_PRINTF(0, "Illegal IP address \"%s\"", s_netaddr);
return 1;
}
//printf("GOT: %s(%08x)",inet_ntoa(foo_addr),foo_addr.s_addr);
if (inet_pton(olsr_cnf->ip_version, s_netaddr, &temp_netmask) <= 0) {
OLSR_PRINTF(0, "Illegal netmask \"%s\"", s_netaddr);
return 1;
}
//printf("/%s(%08x)\n",inet_ntoa(foo_addr),foo_addr.s_addr);
//printf("%s():got->%s/%s\n",__func__,olsr_ip_to_string((union olsr_ip_addr *)&));
the_hna_list = add_to_hna_list(the_hna_list, &temp_net, &temp_netmask);
if (the_hna_list != NULL) {
return 1;
}
return 0;
}
static const struct olsrd_plugin_parameters plugin_parameters[] = {
{ .name = "interval", .set_plugin_parameter = &set_plugin_double, .data = &check_interval },
{ .name = "ping", .set_plugin_parameter = &set_plugin_ping, .data = NULL },
{ .name = "hna", .set_plugin_parameter = &set_plugin_hna, .data = NULL },
};
void olsrd_get_plugin_parameters(const struct olsrd_plugin_parameters **params, int *size)
{
*params = plugin_parameters;
*size = sizeof(plugin_parameters)/sizeof(*plugin_parameters);
}
/**
*Do initialization here
*
*
*This function is called by the my_init
*function in uolsrd_plugin.c
*It is ran _after_ register_olsr_param
*/
int
olsrd_plugin_init(void)
{
pthread_t ping_thread;
//gw_net.v4 = INET_NET;
//gw_netmask.v4 = INET_PREFIX;
//gw_already_added = 0;
//has_available_gw = 0;
/* Remove all local Inet HNA entries */
/*while(remove_local_hna4_entry(&gw_net, &gw_netmask))
{
olsr_printf(1, "HNA Internet gateway deleted\n");
}*/
pthread_create(&ping_thread, NULL, (void *(*)(void *))looped_checks, NULL);
/* Register the GW check */
olsr_register_scheduler_event(&olsr_event_doing_hna, NULL, 3, 4, NULL);
return 1;
}
/**
* Scheduled event to update the hna table,
* called from olsrd main thread to keep the hna table thread-safe
*/
static void
olsr_event_doing_hna(void *foo __attribute__((unused)))
{
struct hna_list *li;
/*
if (has_available_gw == 1 && gw_already_added == 0) {
olsr_printf(1, "Adding OLSR local HNA entry for Internet\n");
add_local_hna4_entry(&gw_net, &gw_netmask);
gw_already_added = 1;
} else if ((has_available_gw == 0) && (gw_already_added == 1)) {
// Remove all local Inet HNA entries /
while(remove_local_hna4_entry(&gw_net, &gw_netmask)) {
olsr_printf(1, "Removing OLSR local HNA entry for Internet\n");
}
gw_already_added = 0;
}
*/
for(li=the_hna_list; li; li=li->next){
if((li->probe_ok==1)&&(li->hna_added==0)){
olsr_printf(1, "Adding OLSR local HNA entry\n");
add_local_hna4_entry(&li->hna_net, &li->hna_netmask);
li->hna_added=1;
}else if((li->probe_ok==0)&&(li->hna_added==1)){
while(remove_local_hna4_entry(&li->hna_net, &li->hna_netmask)) {
olsr_printf(1, "Removing OLSR local HNA entry\n");
}
li->hna_added=0;
}
}
}
/**
* the threaded function which happens within an endless loop,
* reiterated every "Interval" sec (as given in the config or
* the default value)
*/
static void
looped_checks(void *foo __attribute__((unused)))
{
for(;;) {
struct hna_list *li;
struct timespec remainder_spec;
/* the time to wait in "Interval" sec (see connfig), default=5sec */
struct timespec sleeptime_spec = { check_interval, 0L };
for(li = the_hna_list; li; li = li->next){
/* check for gw in table entry and if Ping IPs are given also do pings */
li->probe_ok = check_gw(&li->hna_net,&li->hna_netmask,li->ping_hosts);
//has_available_gw = check_gw(&gw_net, &gw_netmask);
}
while(nanosleep(&sleeptime_spec, &remainder_spec) < 0)
sleeptime_spec = remainder_spec;
}
// return NULL;
}
static int
check_gw(union olsr_ip_addr *net, union olsr_ip_addr *mask, struct ping_list *the_ping_list)
{
char buf[1024], iface[16];
olsr_u32_t gate_addr, dest_addr, netmask;
unsigned int iflags;
int metric, refcnt, use;
int retval = 0;
FILE *fp = fopen(PROCENTRY_ROUTE, "r");
if (!fp)
{
perror(PROCENTRY_ROUTE);
olsr_printf(1, "INET (IPv4) not configured in this system.\n");
return -1;
}
/*
olsr_printf(1, "Genmask Destination Gateway "
"Flags Metric Ref Use Iface\n");
*/
while (fgets(buf, sizeof(buf), fp))
{
int num = sscanf(buf, "%15s %128X %128X %X %d %d %d %128X \n",
iface, &dest_addr, &gate_addr,
&iflags, &refcnt, &use, &metric, &netmask);
if (num < 8)
continue;
/*
olsr_printf(1, "%-15s ", olsr_ip_to_string((union olsr_ip_addr *)&netmask));
olsr_printf(1, "%-15s ", olsr_ip_to_string((union olsr_ip_addr *)&dest_addr));
olsr_printf(1, "%-15s %-6d %-2d %7d %s\n",
olsr_ip_to_string((union olsr_ip_addr *)&gate_addr),
metric, refcnt, use, iface);
*/
if( (iflags & RTF_UP) &&
(metric == 0) &&
(netmask == mask->v4) &&
(dest_addr == net->v4))
{
if ( ((mask->v4==INET_PREFIX)&&(net->v4==INET_NET))&&(!(iflags & RTF_GATEWAY)))
{
fclose(fp);
return retval;
}
/* don't ping, if there was no "Ping" IP addr in the config file */
if (the_ping_list != NULL) {
/*validate the found inet gw by pinging*/
if (ping_is_possible(the_ping_list)) {
olsr_printf(1, "HNA[%08x/%08x](ping is possible) VIA %s detected in routing table.\n", dest_addr,netmask,iface);
retval=1;
}
} else {
olsr_printf(1, "HNA[%08x/%08x] VIA %s detected in routing table.\n", dest_addr,netmask,iface);
retval=1;
}
}
}
fclose(fp);
if(retval == 0){
olsr_printf(1, "HNA[%08x/%08x] is invalid\n", net->v4,mask->v4);
}
return retval;
}
static int
ping_is_possible(struct ping_list *the_ping_list)
{
struct ping_list *list;
for(list = the_ping_list; list; list = list->next) {
char ping_command[50];
snprintf(ping_command, sizeof(ping_command), "ping -c 1 -q %s", list->ping_address);
olsr_printf(1, "\nDo ping on %s ...\n", list->ping_address);
if (system(ping_command) == 0) {
olsr_printf(1, "...OK\n\n");
return 1;
}
olsr_printf(1, "...FAILED\n\n");
}
return 0;
}
/* add the valid IPs to the head of the list */
static struct ping_list *
add_to_ping_list(const char *ping_address, struct ping_list *the_ping_list)
{
struct ping_list *new = malloc(sizeof(struct ping_list));
if(!new)
{
fprintf(stderr, "DYN GW: Out of memory!\n");
exit(0);
}
new->ping_address = strdup(ping_address);
new->next = the_ping_list;
return new;
}
static struct hna_list *
add_to_hna_list(struct hna_list * list_root, union olsr_ip_addr *hna_net, union olsr_ip_addr *hna_netmask )
{
struct hna_list *new = malloc(sizeof(struct hna_list));
if(new == NULL)
{
fprintf(stderr, "DYN GW: Out of memory!\n");
exit(0);
}
//memcpy(&new->hna_net,hna_net,sizeof(union hna_net));
//memcpy(&new->hna_netmask,hna_netmask,sizeof(union hna_netmask));
new->hna_net.v4=hna_net->v4;
new->hna_netmask.v4=hna_netmask->v4;
new->hna_added=0;
new->probe_ok=0;
new->ping_hosts=NULL;
new->next=list_root;
return new;
}
#ifdef WIN32
/*
* Windows ptread compat stuff
*/
static unsigned long __stdcall ThreadWrapper(void *Para)
{
struct ThreadPara *Cast;
void *(*Func)(void *);
void *Arg;
Cast = (struct ThreadPara *)Para;
Func = Cast->Func;
Arg = Cast->Arg;
HeapFree(GetProcessHeap(), 0, Para);
Func(Arg);
return 0;
}
int pthread_create(HANDLE *Hand, void *Attr __attribute__((unused)), void *(*Func)(void *), void *Arg)
{
struct ThreadPara *Para;
unsigned long ThreadId;
Para = HeapAlloc(GetProcessHeap(), 0, sizeof (struct ThreadPara));
if (Para == NULL)
return -1;
Para->Func = Func;
Para->Arg = Arg;
*Hand = CreateThread(NULL, 0, ThreadWrapper, Para, 0, &ThreadId);
if (*Hand == NULL)
return -1;
return 0;
}
int pthread_kill(HANDLE Hand, int Sig __attribute__((unused)))
{
if (!TerminateThread(Hand, 0))
return -1;
return 0;
}
int pthread_mutex_init(HANDLE *Hand, void *Attr __attribute__((unused)))
{
*Hand = CreateMutex(NULL, FALSE, NULL);
if (*Hand == NULL)
return -1;
return 0;
}
int pthread_mutex_lock(HANDLE *Hand)
{
if (WaitForSingleObject(*Hand, INFINITE) == WAIT_FAILED)
return -1;
return 0;
}
int pthread_mutex_unlock(HANDLE *Hand)
{
if (!ReleaseMutex(*Hand))
return -1;
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1