Files
m241Neelima/components/ip_net2-6.9/ipike/src/ipike_dispatcher.c
T
2026-07-30 11:19:44 +05:30

2779 lines
87 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_dispatcher.c,v $ $Revision: 1.119.10.25 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_dispatcher.c,v $
* $Author: yli12 $ $Date: 2016-04-19 07:38:49 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* Sends and receives raw messages from remote peers. */
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipike_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipike_h.h"
#include "ipike_configuration.h"
#include "ipike_configuration_parse.h"
#include "ipike_dispatcher.h"
#include "ipike_isakmp.h"
#include "ipike_pfkeyv2.h"
#include "ipike_payload_nat.h"
#include "ipike_ipsec_sadb.h"
#include "ipike_util.h"
#include "ipike_ipc.h"
#include "ipike_sadb.h"
#include "ipike_http_fetcher.h"
#ifdef IPIKE_USE_EVENT_LOG
#include "ipike_channel.h"
#endif
#include <ipcom_clib.h>
#include <ipcom_sock2.h>
#include <ipcom_os.h>
#include <ipcom_sock6.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
#if !defined(IPIPSEC2) && !defined(IPIPSEC) && !defined(IP_PORT_OSE5)
#define UDP_ENCAP_ESPINUDP 2
#define UDP_ENCAP 100
#endif
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_shell_cmd_list
*===========================================================================
* Description: Responds to ike list requests from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_list(Ip_fd s);
#ifdef IPIKE_USE_PERF_EVAL
/*
*===========================================================================
* ipike_shell_cmd_stat
*===========================================================================
* Description: Responds to ike stat requests from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_stat(Ip_fd fd);
#endif
/*
*===========================================================================
* ipike_shell_cmd_config_dump
*===========================================================================
* Description: Responds to ike config dump requests from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_dump(Ip_fd fd, Ip_u8* data, Ip_u32 len);
/*
*===========================================================================
* ipike_shell_cmd_config_load
*===========================================================================
* Description: Responds to ike config load requests from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_load(Ip_fd fd, Ip_u8* data, Ip_u32 len);
/*
*===========================================================================
* ipike_shell_cmd_config_add
*===========================================================================
* Description: Responds to ike config add request from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_add(Ip_fd fd, Ip_u8* data, Ip_u32 len);
/*
*===========================================================================
* ipike_shell_cmd_config_delete
*===========================================================================
* Description: Responds to ike config delete request from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_delete(Ip_fd fd, Ip_u8* data, Ip_u32 len);
/*
*===========================================================================
* ipike_shell_cmd_mobike
*===========================================================================
* Description: Responds to ike mobike request from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_shell_cmd_mobike(Ip_fd fd, Ip_u8 *data, Ip_u32 len);
/*
*===========================================================================
* ipike_dispath_handle_shell_command
*===========================================================================
* Description: Responds to requests from the shell command(s).
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ipike_error
ipike_dispath_handle_shell_command(Ip_fd fd);
/*
*===========================================================================
* ipike_dispatch_housekeeping_tmo_cb
*===========================================================================
* Description: Is called once every second the check for events.
* Parameters:
* Returns: IPIKE error code.
*
*/
IP_STATIC Ip_bool
ipike_dispatch_housekeeping_tmo_cb(void *unused);
/*
*===========================================================================
* ipike_dispatcher_socket_get
*===========================================================================
*/
IP_STATIC Ipike_socket *
ipike_dispatcher_socket_get(union Ip_sockaddr_union* addr);
/*
*===========================================================================
* ipike_dispatcher_bypass_flow_add
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_bypass_flow_add(union Ip_sockaddr_union *addr_src);
/*
*===========================================================================
* ipike_dispatcher_bypass_flow_remove
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_bypass_flow_remove(union Ip_sockaddr_union *addr_src);
/*
*===========================================================================
* ipike_dispatcher_start_listen
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_dispatcher_start_listen(union Ip_sockaddr_union *addr);
/*
*===========================================================================
* ipike_dispatcher_stop_listen
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_stop_listen(union Ip_sockaddr_union* addr);
#ifdef IPNET
/*
*===========================================================================
* ipike_ip4_addr_to_sockaddr
*===========================================================================
*
*/
#ifdef IPCOM_USE_INET
IP_STATIC void
ipike_ip4_addr_to_sockaddr(struct Ip_sockaddr_in *sin, Ip_u32 in_addr_n);
#endif
/*
*===========================================================================
* ipike_ip6_create_sockaddr
*===========================================================================
*
*/
#ifdef IPCOM_USE_INET6
IP_GLOBAL struct Ip_sockaddr *
ipike_ip6_create_sockaddr(struct Ip_sockaddr_in6 *sin6,
IP_CONST struct Ip_in6_addr *addr,
Ip_u32 ifindex);
#endif
#endif /*#ifdef IPNET */
/*
*===========================================================================
* ipike_dispatch_remove_all_radius_sockets
*===========================================================================
*/
IP_GLOBAL void
ipike_dispatch_remove_all_radius_sockets(void);
#ifdef IPIKE_USE_MIGRATE
/*
*===========================================================================
* ipike_mobike_handler
* Makes shell command obsolete ( FIXME: delete
* shell cmd )
*===========================================================================
*/
IP_GLOBAL Ipike_error ipike_mobike_handler (union Ip_sockaddr_union *old_addr,
union Ip_sockaddr_union *new_addr);
#endif /* #ifdef IPIKE_USE_MIGRATE */
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_dispatcher_flow_add
*===========================================================================
*/
#if 0
IP_STATIC Ipike_error ipike_dispatcher_flow_add(
Ipike_config_flow * flow,
Ip_bool ingress)
{
Ipike_error err;
err = ipike_pfkeyv2_add_flow(flow,
IP_NULL,
IP_NULL,
0,
ingress,
IP_FALSE);
if (IPIKE_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_flow_add() :: "\
"failed to add flow");
}
return err;
}
/*
*===========================================================================
* ipike_dispatcher_flow_remove
*===========================================================================
*/
IP_STATIC Ipike_error ipike_dispatcher_flow_remove(
Ipike_config_flow * flow,
Ip_bool ingress)
{
Ipike_error err;
err = ipike_pfkeyv2_remove_flow(flow,
IP_NULL,
IP_NULL,
0,
ingress,
IP_FALSE);
if (IPIKE_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_flow_remove() :: "\
"failed to remove flow");
}
return err;
}
#endif
/*
*===========================================================================
* ipike_dispatcher_trigger_flows_add
*===========================================================================
*/
IP_STATIC void ipike_dispatcher_trigger_flows_add(void)
{
Ipike_config_flow * flow;
int i;
if (ipike.config.ipsec_sa == IP_NULL)
return;
for ( i = 0; ipike.config.ipsec_sa[i] != IP_NULL; i++)
{
flow = &ipike.config.ipsec_sa[i]->flow;
/* Add all 'acquire' and 'require' flows */
if (flow->type != 0)
{
(void)ipike_pfkeyv2_add_flows(flow,
IP_NULL,
IP_NULL,
0,
IP_FALSE,
IP_FALSE);
}
}
}
/*
*===========================================================================
* ipike_dispatcher_trigger_flows_remove
*===========================================================================
*/
IP_GLOBAL void ipike_dispatcher_trigger_flows_remove(void)
{
Ipike_config_flow * flow;
int i;
if (ipike.config.ipsec_sa == IP_NULL)
return;
for ( i = 0; ipike.config.ipsec_sa[i] != IP_NULL; i++)
{
flow = &ipike.config.ipsec_sa[i]->flow;
/* Add all 'acquire' and 'require' flows */
if (flow->type != 0)
{
(void)ipike_pfkeyv2_remove_flows(flow,
IP_NULL,
IP_NULL,
0,
IP_FALSE,
IP_FALSE);
}
}
}
/*
*===========================================================================
* ipike_config_set_flowtype
*===========================================================================
*/
#if 0
IP_GLOBAL Ipike_error ipike_config_set_flowtype(Ipcom_list *head, Ip_bool add)
{
Ipike_flowtype_flow *ipsec_flowtype,*temp = IP_NULL;
Ipike_error err = IPIKE_SUCCESS;
Ipike_error err2 = IPIKE_FAILED;
ipsec_flowtype = IPCOM_LIST_FIRST(head);
while (IP_NULL != ipsec_flowtype)
{
err = ipike_ipsec_flowtype(&ipsec_flowtype->flow,
ipsec_flowtype->flowtype,
add);
if (IP_NULL != temp && IPIKE_SUCCESS == err2 )
{
ipcom_list_remove(&temp->list);
ipcom_free(temp);
temp = IP_NULL;
}
err2 = err;
if (IPIKE_SUCCESS == err && IP_FALSE == add)
{
temp = ipsec_flowtype; /* remove and removed ok */
}
else
{
temp = IP_NULL; /* fail or add */
}
ipsec_flowtype = IPCOM_LIST_NEXT(&ipsec_flowtype->list);
}
if (IP_NULL != temp && IPIKE_SUCCESS == err2)
{
ipcom_list_remove(&temp->list);
ipcom_free(temp);
temp = IP_NULL;
}
return IPIKE_SUCCESS;
}
#endif
/*
*===========================================================================
* ipike_shell_cmd_list
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_list(Ip_fd s)
{
int sa_count;
Ip_u8* data;
Ip_size_t data_len;
struct Ipike_ipd_sa_info *sa_info_list;
Ipike_error err = IPIKE_SUCCESS;
IPIKE_CODE_LOCK();
sa_count = ipike_sadb_num_entries();
data_len = (Ip_size_t)sa_count * sizeof(struct Ipike_ipd_sa_info) + sizeof(sa_count);
data = ipcom_malloc(data_len);
if (data == IP_NULL)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
goto cleanup;
}
sa_info_list = (struct Ipike_ipd_sa_info*)(data + sizeof(sa_count));
sa_count = ipike_sadb_get_sa_information(sa_info_list);
ipcom_memcpy(data, (void*)&sa_count, sizeof(sa_count));
if (ipcom_send(s, data, data_len, 0) != (Ip_ssize_t) data_len)
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_list: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
goto cleanup;
}
IPIKE_CODE_UNLOCK();
cleanup:
(void)err; /* lint */
ipcom_free(data);
return IPIKE_SUCCESS;
}
#ifdef IPIKE_USE_PERF_EVAL
/*
*===========================================================================
* ipike_shell_cmd_stat
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_stat(Ip_fd fd)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_perf my_stat;
struct Ip_timeval now;
Ip_u32 diff;
Ip_u32 exchanges;
Ip_u32 entries;
IPIKE_CODE_LOCK();
ipcom_microtime(&now);
diff = (Ip_u32) (now.tv_sec - ipike.start.tv_sec); /* Uptime */
exchanges = ipike.active_exchanges;
entries = (Ip_u32) ipike_sadb_num_entries();
ipcom_memcpy((void*)&my_stat, (void*)&ipike_perf, sizeof(Ipike_perf));
if ((ipcom_send(fd, &diff, sizeof(diff), 0) != sizeof(diff)) ||
(ipcom_send(fd, &exchanges, sizeof(exchanges), 0) != sizeof(exchanges)) ||
(ipcom_send(fd, &entries, sizeof(entries), 0) != sizeof(entries)) ||
(ipcom_send(fd, &my_stat, sizeof(my_stat), 0) != sizeof(my_stat)))
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_stat: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
IPIKE_CODE_UNLOCK();
return err;
}
#endif
/*
*===========================================================================
* ipike_shell_cmd_config_dump
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_dump(Ip_fd fd, Ip_u8* data, Ip_u32 len)
{
Ipike_error err = IPIKE_SUCCESS;
char* filename = IP_NULL;
void* ctx = IP_NULL;
char* buf = IP_NULL;
Ip_size_t buf_len = 0;
filename = (char*)data;
if ((len <= 1) || (filename[len-1] != 0))
{
IPCOM_LOG0(ERR, "ipike_shell_cmd_config_dump: bad file name");
err = IPIKE_FAILED;
}
else
{
ctx = ipike_config_api_new(IP_TRUE);
if (IP_NULL == ctx)
err = IPIKE_OUT_OF_MEMORY;
else
err = ipike_config_api_export(ctx, IP_NULL, &buf_len);
if (IPIKE_SUCCESS == err)
if (IP_NULL == (buf = ipcom_malloc(buf_len)))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
if (IPIKE_SUCCESS == err)
err = ipike_config_api_export(ctx, buf, &buf_len);
if (IPIKE_SUCCESS == err)
err = ipike_write_file(filename, (Ip_u8*)buf, buf_len);
ipcom_free(buf);
ipike_config_api_free(ctx);
}
if (IPIKE_SUCCESS == err)
buf = "Configuration dumped";
else
buf = "Failed to dump configuration";
buf_len = ipcom_strlen(buf) + 1;
len = ip_htonl(buf_len);
if ((ipcom_send(fd, &len, sizeof(len), 0) != sizeof(len)) ||
(ipcom_send(fd, buf, buf_len, 0) != (Ip_ssize_t)buf_len))
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_config_dump: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
return err;
}
/*
*===========================================================================
* ipike_shell_cmd_config_load
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_load(Ip_fd fd, Ip_u8* data, Ip_u32 len)
{
Ipike_error err = IPIKE_SUCCESS;
char* filename = IP_NULL;
void* ctx = IP_NULL;
Ip_u8* buf = IP_NULL;
Ip_size_t buf_len = 0;
filename = (char*)data;
if ((len <= 1) || (filename[len-1] != 0))
{
IPCOM_LOG0(ERR, "ipike_shell_cmd_config_dump: bad file name");
err = IPIKE_FAILED;
}
else
{
err = ipike_read_file(filename, &buf, &buf_len);
ipike_dispatcher_trigger_flows_remove();
if (IPIKE_SUCCESS == err)
{
ctx = ipike_config_api_new(ipike_config_should_append((char*)buf, buf_len));
if (IP_NULL == ctx)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
}
if (IPIKE_SUCCESS == err)
err = ipike_config_api_import(ctx, (char*)buf, buf_len);
if (IPIKE_SUCCESS == err)
err = ipike_config_api_commit(ctx);
ipcom_free(buf);
ipike_config_api_free(ctx);
}
if (IPIKE_SUCCESS == err)
buf = (Ip_u8*)"Configuration loaded";
else
buf = (Ip_u8*)"Failed to load configuration";
buf_len = ipcom_strlen((char*)buf) + 1;
len = ip_htonl(buf_len);
if ((ipcom_send(fd, &len, sizeof(len), 0) != sizeof(len)) ||
(ipcom_send(fd, buf, buf_len, 0) != (Ip_ssize_t)buf_len))
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_config_dump: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
return err;
}
/*
*===========================================================================
* ipike_shell_cmd_config_add
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_add(Ip_fd fd, Ip_u8* data, Ip_u32 len)
{
Ipike_error err = IPIKE_SUCCESS;
char* content = IP_NULL;
void* ctx = IP_NULL;
Ip_u8* buf = IP_NULL;
Ip_size_t buf_len = 0;
content = (char*)data;
if ((len <= 1) || (content[len-1] != 0))
{
IPCOM_LOG0(ERR, "ipike_shell_cmd_config_add: bad content");
err = IPIKE_FAILED;
}
else
{
ctx = ipike_config_api_new(IP_TRUE);
if (IP_NULL == ctx)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
if (IPIKE_SUCCESS == err)
err = ipike_config_api_import(ctx, content, ipcom_strlen(content));
if (IPIKE_SUCCESS == err)
err = ipike_config_api_commit(ctx);
ipike_config_api_free(ctx);
if (IPIKE_SUCCESS == err)
buf = (Ip_u8*)"Configuration updated";
else
buf = (Ip_u8*)"Failed to update configuration";
buf_len = ipcom_strlen((char*)buf) + 1;
len = ip_htonl(buf_len);
if ((ipcom_send(fd, &len, sizeof(len), 0) != sizeof(len)) ||
(ipcom_send(fd, buf, buf_len, 0) != (Ip_ssize_t)buf_len))
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_config_add: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
}
return err;
}
/*
*===========================================================================
* ipike_shell_cmd_config_delete
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_config_delete(Ip_fd fd, Ip_u8* data, Ip_u32 len)
{
char* content = IP_NULL;
Ip_u8* buf = IP_NULL;
Ip_size_t buf_len = 0;
void* ctx = IP_NULL;
void* ctx2 = IP_NULL;
int pos = 0;
char id[IPIKE_CONFIG_MAX_ID_LEN] = {0};
Ipike_config_api_ike_sa ike = {0};
Ipike_config_api_ipsec_sa ipsec = {0};
Ipike_error err = IPIKE_SUCCESS;
content = (char*)data;
if ((len <= 1) || (content[len-1] != 0))
{
IPCOM_LOG0(ERR, "ipike_shell_cmd_config_delete: bad content");
err = IPIKE_FAILED;
}
else
{
ctx = ipike_config_api_new(IP_FALSE);
ctx2 = ipike_config_api_new(IP_TRUE);
if ((IP_NULL == ctx) || (IP_NULL == ctx2))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
if (IPIKE_SUCCESS == err)
{
err = ipike_config_api_import(ctx, content, ipcom_strlen(content));
if (IPIKE_SUCCESS == err)
{
pos = IPIKE_CONFIG_INVALID_VALUE;
while (ipike_config_api_get_next_ike_sa(ctx, id, &ike, &pos) == 0)
{
(void)ipike_config_api_set_ike_sa(ctx2, id, IP_NULL);
ipike_config_api_release_ike_sa(&ike);
}
pos = IPIKE_CONFIG_INVALID_VALUE;
while (ipike_config_api_get_next_ipsec_sa(ctx, id, &ipsec, &pos) == 0)
{
(void)ipike_config_api_set_ipsec_sa(ctx2, id, IP_NULL);
ipike_config_api_release_ipsec_sa(&ipsec);
}
}
}
if (IPIKE_SUCCESS == err)
err = ipike_config_api_commit(ctx2);
ipike_config_api_free(ctx);
ipike_config_api_free(ctx2);
if (IPIKE_SUCCESS == err)
buf = (Ip_u8*)"Configuration updated";
else
buf = (Ip_u8*)"Failed to update configuration";
buf_len = ipcom_strlen((char*)buf) + 1;
len = ip_htonl(buf_len);
if ((ipcom_send(fd, &len, sizeof(len), 0) != sizeof(len)) ||
(ipcom_send(fd, buf, buf_len, 0) != (Ip_ssize_t)buf_len))
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_config_delete: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
}
return err;
}
/*
*===========================================================================
* ipike_shell_cmd_mobike
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_shell_cmd_mobike(Ip_fd fd, Ip_u8 *data, Ip_u32 len)
{
Ipike_error err = IPIKE_SUCCESS;
char *str_old = IP_NULL;
char *str_new = IP_NULL;
const char *resp_buf = IP_NULL;
Ip_u32 resp_len = 0;
union Ip_sockaddr_union old_addr;
union Ip_sockaddr_union new_addr;
IPIKE_CODE_LOCK();
/* Format: "<old address> <new address>" */
str_old = (char*)data;
if ((len <= 1) ||
(str_old[len-1] != 0) ||
((str_new = ipcom_strchr(str_old, ' ')) == IP_NULL))
{
IPCOM_LOG0(ERR, "ipike_shell_cmd_mobike: bad content");
err = IPIKE_FAILED;
}
else
{
*(str_new++) = 0;
if (ipike_addr_set(&old_addr, str_old) != IPIKE_SUCCESS)
{
resp_buf = "Invalid old ip address.";
}
else if (ipike_addr_set(&new_addr, str_new) != IPIKE_SUCCESS)
{
resp_buf = "Invalid new ip address.";
}
else if (ipike_addr_compare(&old_addr, &new_addr) == 0)
{
resp_buf = "Bad new ip address, same as old.";
}
else
{
ipike_addr_set_port(&old_addr, ipike.port);
ipike_addr_set_port(&new_addr, ipike.port);
(void)ipike_dispatcher_stop_listen(&old_addr);
if ( ipike_dispatcher_socket_get(&new_addr) == IP_NULL &&
ipike_dispatcher_start_listen(&new_addr) != IPIKE_SUCCESS)
{
(void)ipike_dispatcher_start_listen(&old_addr);
resp_buf = "Failed to start listen on new ip address.";
}
else if (ipike_sadb_initiate_address_update(&old_addr, &new_addr) != IPIKE_SUCCESS)
{
(void)ipike_dispatcher_stop_listen(&new_addr);
(void)ipike_dispatcher_start_listen(&old_addr);
resp_buf = "Failed to initiate address update.";
}
else
{
resp_buf = "Address update initiated.";
}
}
resp_len = (Ip_u32) ipcom_strlen(resp_buf) + 1;
IPCOM_LOG1(DEBUG, "ipike_shell_cmd_mobike: %s", resp_buf);
len = ip_htonl(resp_len);
if (fd != IP_INVALID_SOCKET)
{
if ((ipcom_send(fd, &len, sizeof(len), 0) != sizeof(len)) ||
(ipcom_send(fd, resp_buf, resp_len, 0) != (Ip_ssize_t)resp_len))
{
IPCOM_LOG1(ERR, "ipike_shell_cmd_mobike: send failed: %s", ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
}
}
IPIKE_CODE_UNLOCK();
return err;
}
/*
*===========================================================================
* ipike_shell_cmd
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_shell_cmd(Ip_u8 cmd, Ip_fd fd, Ip_u8 *buf, Ip_u32 len)
{
Ipike_error err = IPIKE_SUCCESS;
switch (cmd)
{
case IPIKE_CMD_LIST:
err = ipike_shell_cmd_list(fd);
break;
#ifdef IPIKE_USE_PERF_EVAL
case IPIKE_CMD_STAT:
err = ipike_shell_cmd_stat(fd);
break;
#endif
case IPIKE_CMD_CONFIG_DUMP:
err = ipike_shell_cmd_config_dump(fd, buf, len);
break;
case IPIKE_CMD_CONFIG_LOAD:
err = ipike_shell_cmd_config_load(fd, buf, len);
break;
case IPIKE_CMD_CONFIG_ADD:
err = ipike_shell_cmd_config_add(fd, buf, len);
break;
case IPIKE_CMD_CONFIG_DELETE:
err = ipike_shell_cmd_config_delete(fd, buf, len);
break;
case IPIKE_CMD_MOBIKE:
err = ipike_shell_cmd_mobike(fd, buf, len);
break;
default:
break;
}
return err;
}
/*
*===========================================================================
* ipike_dispath_handle_shell_command
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_dispath_handle_shell_command(Ip_fd fd)
{
Ipike_error err = IPIKE_SUCCESS;
Ip_u8 cmd = 0;
Ip_u32 len = 0;
Ip_u8* buf = IP_NULL;
fd = ipcom_accept(fd, IP_NULL, 0);
if (fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR,
"ipike_dispath_handle_shell_command: accept failed - %s",
ipcom_strerror(ipcom_errno));
}
else
{
if ((ipcom_socketread(fd, &cmd, sizeof(cmd)) <= 0) ||
(ipcom_socketread(fd, &len, sizeof(len)) <= 0))
{
IPCOM_LOG0(ERR, "ipike_dispath_handle_shell_command: read command failed");
err = IPIKE_FAILED;
}
else
{
len = ip_htonl(len);
if (len > 0)
{
buf = ipcom_malloc(len);
if (buf == IP_NULL)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else if (ipcom_socketread(fd, buf, len) < 0)
{
IPCOM_LOG0(ERR, "ipike_dispath_handle_shell_command: read command data failed");
err = IPIKE_FAILED;
}
}
if (IPIKE_SUCCESS == err)
{
err = ipike_shell_cmd(cmd, fd, buf, len);
}
if (IP_NULL != buf)
ipcom_free(buf);
}
ipcom_socketclose(fd);
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_dispatch_housekeeping_tmo_cb
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_dispatch_housekeeping_tmo_cb(void *unused)
{
Ip_bool cont = IP_TRUE;
(void)unused; /* lint */
IPIKE_CODE_LOCK();
++ipike.disp.ticks;
if (ipike.disp.ticks % 10 == 1)
{
if (IPIKE_SUCCESS != ipike_dispatch_start_sa_negotiation(IP_NULL))
{
/* Unrecoverable error, so schedule for shutdown */
ipike.schedule_shutdown = IP_TRUE;
cont = IP_FALSE;
goto out;
}
}
/* Check livenes */
if ( ipike.liveness_timer_resolution != 0 &&
ipike.disp.ticks % ipike.liveness_timer_resolution == 1 )
{
ipike_ipsec_sadb_check_liveness();
}
/* Send NAT Keep-Alive */
if ( ipike.keepalive_nat != 0 &&
ipike.disp.ticks % ipike.keepalive_nat == 1)
{
(void) ipike_sadb_send_nat_keepalive();
}
out:
IPIKE_CODE_UNLOCK();
return cont;
}
/*
*===========================================================================
* ipike_dispatcher_bypass_flow_add
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_bypass_flow_add(
union Ip_sockaddr_union *addr_src)
{
Ipike_config_netobj src;
Ipike_config_netobj dst;
Ipike_error err;
/* Copy source address */
ipike_config_netobj_from_addr(&src, addr_src);
/* Make an "any" destination address */
ipike_config_netobj_from_addr(&dst, addr_src);
ipcom_memset(ipike_addr_get_ptr(&dst.addr),
0x00,
ipike_addr_get_len(&dst.addr));
ipcom_memset(ipike_addr_get_ptr(&dst.high_or_mask),
0x00,
ipike_addr_get_len(&dst.high_or_mask));
ipike_config_netobj_set_port_low(&dst, 0);
ipike_config_netobj_set_port_high(&dst, 0);
err = ipike_pfkeyv2_add_flow_ext(&src,
&dst,
0,
IP_IPPROTO_UDP,
IP_NULL,
IP_NULL,
0,
IP_FALSE,
IP_FALSE);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_bypass_flow_add() :: "\
"failed to add egress bypass flow");
}
/* Make an "any" source address */
ipcom_memset(ipike_addr_get_ptr(&src.addr),
0x00,
ipike_addr_get_len(&src.addr));
ipcom_memset(ipike_addr_get_ptr(&src.high_or_mask),
0x00,
ipike_addr_get_len(&src.high_or_mask));
ipike_config_netobj_set_port_low(&src, 0);
ipike_config_netobj_set_port_high(&src, 0);
/* Destination address */
ipike_config_netobj_from_addr(&dst, addr_src);
err = ipike_pfkeyv2_add_flow_ext(&src,
&dst,
0,
IP_IPPROTO_UDP,
IP_NULL,
IP_NULL,
0,
IP_TRUE,
IP_FALSE);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_bypass_flow_add() :: "\
"failed to add ingress bypass flow");
}
}
/*
*===========================================================================
* ipike_dispatcher_bypass_flow_remove
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_bypass_flow_remove(
union Ip_sockaddr_union *addr_src)
{
Ipike_config_netobj src;
Ipike_config_netobj dst;
Ipike_error err;
/* Copy source address */
ipike_config_netobj_from_addr(&src, addr_src);
/* Make an "any" destination address */
ipike_config_netobj_from_addr(&dst, addr_src);
ipcom_memset(ipike_addr_get_ptr(&dst.addr),
0x00,
ipike_addr_get_len(&dst.addr));
ipcom_memset(ipike_addr_get_ptr(&dst.high_or_mask),
0x00,
ipike_addr_get_len(&dst.high_or_mask));
ipike_config_netobj_set_port_low(&dst, 0);
ipike_config_netobj_set_port_high(&dst, 0);
err = ipike_pfkeyv2_remove_flow_ext(&src,
&dst,
0,
IP_IPPROTO_UDP,
IP_NULL,
IP_NULL,
0,
IP_FALSE,
IP_FALSE);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_bypass_flow_remove() :: "\
"failed to remove egress bypass flow");
}
/* Make an "any" source address */
ipcom_memset(ipike_addr_get_ptr(&src.addr),
0x00,
ipike_addr_get_len(&src.addr));
ipcom_memset(ipike_addr_get_ptr(&src.high_or_mask),
0x00,
ipike_addr_get_len(&src.high_or_mask));
ipike_config_netobj_set_port_low(&src, 0);
ipike_config_netobj_set_port_high(&src, 0);
/* Destination address */
ipike_config_netobj_from_addr(&dst, addr_src);
err = ipike_pfkeyv2_remove_flow_ext(&src,
&dst,
0,
IP_IPPROTO_UDP,
IP_NULL,
IP_NULL,
0,
IP_TRUE,
IP_FALSE);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_bypass_flow_remove() :: "\
"failed to remove ingress bypass flow");
}
}
/*
*===========================================================================
* ipike_dispatcher_socket_destroy
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_socket_destroy(
Ipike_socket * socket)
{
IPCOM_LOG3(DEBUG2, "ipike_dispatcher_socket_destroy() :: "\
"closing listening socket %s:%d (%d)",
ipike_addr_to_str(&socket->addr),
ipike_addr_get_port(&socket->addr),
socket->fd);
if (socket->fd != IP_INVALID_SOCKET)
ipcom_socketclose(socket->fd);
ipike_dispatcher_bypass_flow_remove(&socket->addr);
ipcom_free(socket);
}
/*
*===========================================================================
* ipike_dispatcher_socket_get
*===========================================================================
*/
IP_STATIC Ipike_socket *
ipike_dispatcher_socket_get(union Ip_sockaddr_union* addr)
{
Ipike_socket * socket = IP_NULL;
for (socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_next(&socket->list))
{
/* TODO: Match with socket->addr instead of fd */
if (ipike_addr_match_socket(addr, socket->fd))
return socket;
}
IPCOM_LOG1(ERR, "ipike_dispatcher_socket_get() :: No socket found for %s",
ipike_addr_to_str(addr));
return IP_NULL;
}
/*
*===========================================================================
* ipike_dispatcher_socket_create
*===========================================================================
*/
IP_STATIC Ipike_socket *
ipike_dispatcher_socket_create(union Ip_sockaddr_union * addr)
{
Ipike_socket * socket = IP_NULL;
Ip_u32 buf_size = 0;
Ip_fd fd = IP_INVALID_SOCKET;
int ret = IPCOM_SUCCESS;
int on = 1;
#ifdef IPIKE_USE_PKTINFO
int popt = -1;
int popt1 = -1;
int j = 0;
#endif
buf_size = (Ip_u32)ipcom_sysvar_get_as_int("ipike.isakmp_sock_buf_size", 10000);
/* Create socket */
fd = ipcom_socket(addr->sa.sa_family, IP_SOCK_DGRAM, IP_IPPROTO_UDP);
if (fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "ipike_dispatcher_socket_create() ::"\
"failed to create socket - %s",
ipcom_strerror(ipcom_errno));
return IP_NULL;
}
/* Set the send and receive buffer size of the socket */
ret = ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_SNDBUF,
&buf_size, sizeof(buf_size));
if (ret < 0)
{
IPCOM_LOG1(ERR, "ipike_dispatcher_start_listen() :: "\
"failed to set send buffer: %s",
ipcom_strerror(ipcom_errno));
goto errout;
}
ret = ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_RCVBUF,
&buf_size, sizeof(buf_size));
if (ret < 0)
{
IPCOM_LOG1(ERR, "ipike_dispatcher_start_listen() :: "\
"failed to set recv buffer: %s",
ipcom_strerror(ipcom_errno));
goto errout;
}
ret = ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_REUSEADDR,
&on, sizeof(on));
if (ret < 0)
{
IPCOM_LOG1(ERR, "ipike_dispatcher_start_listen() :: "\
"failed to set reuse address: %s",
ipcom_strerror(ipcom_errno));
goto errout;
}
#if !defined(IPIPSEC2) && !defined(IPIPSEC) && !defined(IP_PORT_OSE5)
/* Native IPSec will require an extra flag for NAT Traversal socket */
if (ipike_addr_get_port(addr) == ipike.port_nat)
{
int option = UDP_ENCAP_ESPINUDP;
ret = ipcom_setsockopt(fd, IP_IPPROTO_UDP, UDP_ENCAP,
&option, sizeof(option));
if (ret < 0)
{
IPCOM_LOG1(ERR, "ipike_dispatcher_start_listen() :: "\
"failed to set udp encap option: %s",
ipcom_strerror(ipcom_errno));
goto errout;
}
}
#endif
#ifdef IPNET
#ifdef IP_SO_X_BYPASS_FLOW
/* Flag the socket as bypass socket */
ret = ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_X_BYPASS_FLOW,
&on, sizeof(on));
if (ret < 0)
{
IPCOM_LOG1(WARNING, "ipike_dispatcher_start_listen() :: "\
"failed to set bypass flow: %s",
ipcom_strerror(ipcom_errno));
}
#endif /* IP_SO_X_BYPASS_FLOW */
#ifdef IP_UDP_NAT_T_RFC3948
/* Flag the socket as UDP encap according to RFC3948 */
if (ipike_addr_get_port(addr) == ipike.port_nat)
{
int option = IP_UDP_NAT_T_RFC3948;
ret = ipcom_setsockopt(fd, IP_IPPROTO_UDP, IP_UDP_NAT_T,
&option, sizeof(option));
if (ret < 0)
{
IPCOM_LOG1(WARNING, "ipike_dispatcher_start_listen() :: "\
"failed to set udp encap option: %s",
ipcom_strerror(ipcom_errno));
}
}
#endif /*IP_UDP_NAT_T_RFC3948 */
#ifdef IPIKE_USE_PKTINFO
switch (addr->sa.sa_family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
popt = IP_IPPROTO_IP;
popt1 = IP_IP_PKTINFO;
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
popt = IP_IPPROTO_IPV6;
popt1 = IP_IPV6_RECVPKTINFO;
break;
#endif
default:
popt1 = -1;
break;
}
if (popt1 > 0)
{
j = 1;
if (ipcom_setsockopt(fd, popt, popt1, &j, sizeof(j)) < 0)
{
IPCOM_LOG3(ERR, "Failed set pktinfo options %s[%d] (%s):",
ipike_addr_to_str(addr),
ipike_addr_get_port(addr),
ipcom_strerror(ipcom_errno));
goto errout;
}
}
#endif /* #ifdef IPIKE_USE_PKTINFO */
#endif /* IPNET */
/* Bind socket */
ret = ipcom_bind(fd, (struct Ip_sockaddr*) addr, IPCOM_SA_LEN_GET(&addr->sa));
if (ret < 0)
{
IPCOM_LOG3(ERR, "Failed to bind %s[%d] (%s)",
ipike_addr_to_str(addr),
ipike_addr_get_port(addr),
ipcom_strerror(ipcom_errno));
goto errout;
}
/* Add input and output bypass flow */
ipike_dispatcher_bypass_flow_add(addr);
socket = ipcom_calloc(1, sizeof(Ipike_socket));
if (socket == IP_NULL)
goto errout;
socket->fd = fd;
(void)ipike_addr_copy(&socket->addr, addr);
/* Success */
IPCOM_LOG3(INFO, "ipike_dispatcher_socket_create() :: listening at %s:%d (%d)",
ipike_addr_to_str(&socket->addr),
ipike_addr_get_port(&socket->addr),
socket->fd);
return socket;
errout:
IPCOM_LOG2(ERR, "ipike_dispatcher_socket_create() :: "\
"failed to create socket at %s:%d",
ipike_addr_to_str(addr), ipike_addr_get_port(addr));
ipcom_socketclose(fd);
return IP_NULL;
}
/*
*===========================================================================
* ipike_dispatcher_stop_listen
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_stop_listen(
union Ip_sockaddr_union *addr)
{
Ipike_socket * socket = IP_NULL;
Ipike_socket * next = IP_NULL;
socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
while ( socket != IP_NULL)
{
next = (Ipike_socket *) ipcom_list_next(&socket->list);
/* Just compare addresses, not port */
if (ipike_addr_are_equal(&socket->addr, addr))
{
/* Remove from list */
ipcom_list_remove(&socket->list);
ipike_dispatcher_socket_destroy(socket);
}
socket = next;
}
}
/*
*===========================================================================
* ipike_dispatcher_start_listen
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_dispatcher_start_listen(
union Ip_sockaddr_union *addr)
{
Ipike_socket * socket = IP_NULL;
Ipike_socket * socket_nat = IP_NULL;
(void)ipike_addr_set_port(addr, ipike.port);
socket = ipike_dispatcher_socket_create(addr);
if (socket == IP_NULL)
goto errout;
if (ipike.port_nat != 0)
{
/* Create NAT-T socket */
(void)ipike_addr_set_port(addr, ipike.port_nat);
socket_nat = ipike_dispatcher_socket_create(addr);
if ( socket_nat == IP_NULL )
goto errout;
}
/* Add socket(s) to list */
ipcom_list_insert_last(&ipike.disp.sockets, &socket->list);
if (socket_nat != IP_NULL)
ipcom_list_insert_last(&ipike.disp.sockets, &socket_nat->list);
return IPIKE_SUCCESS;
errout:
if (socket != IP_NULL)
ipike_dispatcher_socket_destroy(socket);
#if 0
if (socket_nat != IP_NULL)
ipike_dispatcher_socket_destroy(socket_nat);
#endif
return IPIKE_FAILED;
}
#ifdef IPNET
/*
*===========================================================================
* ipike_ip4_addr_to_sockaddr
*===========================================================================
* Description: Creates a socket address structure for the specified
* IPv4 address
* Parameters: sin - buffer to store the socket address.
* in_addr_n - an IPv4 address
* Returns:
*
*/
#ifdef IPCOM_USE_INET
IP_STATIC void
ipike_ip4_addr_to_sockaddr(struct Ip_sockaddr_in *sin, Ip_u32 in_addr_n)
{
ipcom_memset(sin, 0, sizeof(struct Ip_sockaddr_in));
sin->sin_family = IP_AF_INET;
IPCOM_SA_LEN_SET(sin, sizeof(struct Ip_sockaddr_in));
sin->sin_addr.s_addr = in_addr_n;
}
#endif
/*
*===========================================================================
* ipike_ip6_create_sockaddr
*===========================================================================
* Description: Creates a socket address structure for the specified
* IPv6 address
* Parameters: sin6 - buffer to store the socket address.
* addr - an IPv6 address.
* ifindex - interface that will be use with this address
* Returns: The socket address for the specified IPv6 address.
*
*/
#ifdef IPCOM_USE_INET6
IP_GLOBAL struct Ip_sockaddr *
ipike_ip6_create_sockaddr(struct Ip_sockaddr_in6 *sin6,
IP_CONST struct Ip_in6_addr *addr,
Ip_u32 ifindex)
{
ipcom_memset(sin6, 0, sizeof(struct Ip_sockaddr_in6));
sin6->sin6_family = IP_AF_INET6;
IPCOM_SA_LEN_SET(sin6, sizeof(struct Ip_sockaddr_in6));
/* ipnet ip6 set addr */
ipcom_memcpy(&sin6->sin6_addr, addr, sizeof(struct Ip_in6_addr));
/* Forget about zones for now*/
sin6->sin6_scope_id = ifindex;
return (struct Ip_sockaddr *) sin6;
}
#endif
#endif /*#ifdef IPNET*/
/*
*===========================================================================
* ipike_dispatcher_destroy_sockets
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_destroy_sockets(void)
{
Ipike_socket * socket = IP_NULL;
/* CODE LOCK MUST BE HELD */
for ( socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets))
{
/* Remove from list */
ipcom_list_remove(&socket->list);
/* Destroy socket */
ipike_dispatcher_socket_destroy(socket);
}
}
/*
*===========================================================================
* ipike_dispatcher_reconfigure_notify
*===========================================================================
*/
IP_STATIC void
ipike_dispatcher_reconfigure_notify(void)
{
Ipike_socket * socket = IP_NULL;
/* CODE LOCK MUST BE HELD */
ipcom_atomic_set(&ipike.disp.reconfigure, 1);
/* Signal reconfigure by shutting the listening sockets */
for ( socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_next(&socket->list))
{
ipcom_shutdown(socket->fd, IP_SHUT_RDWR);
}
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_receive_message
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_receive_message(Ipike_message *msg)
{
Ip_ssize_t recv_len;
Ip_socklen_t addr_len;
Ipike_error err;
Ip_fd_set fd_read;
Ip_fd_set fd_write;
Ip_fd fd = IP_INVALID_SOCKET;
int num;
int retry_count = 0 ;
Ip_u32 i;
int width;
int select_errors = 0;
Ipike_socket * socket;
#ifdef IPIKE_USE_PKTINFO
struct Ip_msghdr pi_msg;
struct Ip_iovec pi_vec;
union Ip_sockaddr_union pi_src;
struct Ip_cmsghdr *cmsghdr;
Ip_u16 local_port;
#endif
(void)fd; /* lint */
msg->data.value = IP_NULL;
msg->data.len = 0;
recv_len = 0;
do {
IP_FD_ZERO(&fd_read);
IP_FD_ZERO(&fd_write);
IP_FD_SET(ipike.ipd, &fd_read);
IP_FD_SET(ipike.pfkeyv2.sock, &fd_read);
width = IP_MAX(ipike.ipd, ipike.pfkeyv2.sock);
IP_FD_SET(ipike.disp.shell_cmd_sock, &fd_read);
width = IP_MAX(width, ipike.disp.shell_cmd_sock);
/* No lock needed, only this thread is allowed to modify the list */
for ( socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_next(&socket->list))
{
IP_FD_SET(socket->fd, &fd_read);
width = IP_MAX(socket->fd, width);
}
#ifdef IPIKE_USE_RADIUS
i = 0;
while ((fd = ipike_dispatch_enum_radius_socket(&i)) != IP_INVALID_SOCKET)
{
IP_FD_SET(fd, &fd_read);
width = IP_MAX(fd, width);
}
#endif
if ( (fd = ipike_http_fetcher_add_fds(&fd_read, &fd_write)) != -1 )
width = IP_MAX(fd, width);
#ifdef IPIKE_USE_EVENT_LOG
if ( (fd = ipike_event_server_add_fds(&fd_read, &fd_write)) != -1 )
width = IP_MAX(fd, width);
#endif
num = ipcom_tmo2_select(ipike.tmo_head, width + 1, &fd_read, &fd_write, IP_NULL, IP_NULL);
ip_assert(num != 0); /* 0=timeout but that can not happen since no timeout */
/* Check for reconfigure */
if (ipcom_atomic_get(&ipike.disp.reconfigure))
{
IPCOM_LOG0(DEBUG, "ipike_receive_message() :: "\
"reconfigure event received");
ipike_dispatcher_reconfigure();
ipcom_atomic_set(&ipike.disp.reconfigure, 0);
continue;
}
if (num < 0)
{
select_errors++;
/* A bad file descriptor error could be perfectly valid result since
* it might have been closed during a timeout. Just try again if this
* was the first error */
if ( select_errors <= 1 )
continue;
IPCOM_LOG1(ERR, "ipike_receive_message() :: ipcom_tmo2_select failed (%s)",
ipcom_strerror(ipcom_errno));
err = IPIKE_RECEIVE_FAILED;
goto cleanup;
}
/* Success, reset error counter */
select_errors = 0;
/* Verify if IPIKE is scheduled for shutdown */
if (ipike.schedule_shutdown)
{
/* Set fail and IPIKE will shutdown */
IPCOM_LOG0(DEBUG, "ipike_receive_message() :: shutdown scheduled");
err = IPIKE_SHUTDOWN;
goto cleanup;
}
if (IP_FD_ISSET(ipike.ipd, &fd_read))
{
/* No code lock, will be handled for each ipd command */
err = ipike_process_ipd_msg(ipike.ipd);
if (IPIKE_SUCCESS != err)
{
if (IPIKE_SHUTDOWN != err)
IPCOM_LOG0(ERR, "ipike_receive_message() :: failed to process ipd message");
goto cleanup;
}
continue;
}
if (IP_FD_ISSET(ipike.pfkeyv2.sock, &fd_read))
{
IPIKE_CODE_LOCK();
err = ipike_pfkeyv2_process_socket_event();
IPIKE_CODE_UNLOCK();
if (IPIKE_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipike_receive_message() :: failed to process pfkey message");
goto cleanup;
}
continue;
}
if (IP_FD_ISSET(ipike.disp.shell_cmd_sock, &fd_read))
{
/* No code lock, will be handled for each shell command */
err = ipike_dispath_handle_shell_command(ipike.disp.shell_cmd_sock);
if (IPIKE_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipike_receive_message() :: failed to process ike command");
goto cleanup;
}
continue;
}
#ifdef IPIKE_USE_RADIUS
i = 0;
IPIKE_CODE_LOCK();
while ((fd = ipike_dispatch_enum_radius_socket(&i)) != IP_INVALID_SOCKET)
{
if (IP_FD_ISSET(fd, &fd_read))
{
ipike_radius_process_dispatcher_event(fd);
break;
}
}
IPIKE_CODE_UNLOCK();
if (fd != IP_INVALID_SOCKET)
continue;
#endif /* IPIKE_USE_RADIUS */
IPIKE_CODE_LOCK();
i = (Ip_u32) ipike_http_fetcher_process(&fd_read, &fd_write);
IPIKE_CODE_UNLOCK();
if ( i > 0 )
continue;
#ifdef IPIKE_USE_EVENT_LOG
IPIKE_CODE_LOCK();
i = ipike_event_server_process(&fd_read, &fd_write);
IPIKE_CODE_UNLOCK();
if ( i > 0 )
continue;
#endif /* IPIKE_USE_EVENT_LOG */
/* No lock needed, only this thread is allowed to modify the list */
for ( socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_next(&socket->list))
{
if (IP_FD_ISSET(socket->fd, &fd_read))
break;
}
/* No data on any socket */
if (socket == IP_NULL)
continue;
#ifdef IPIKE_USE_PKTINFO
/* Initialize vector */
pi_vec.iov_base = ipike.disp.recv_buf;
pi_vec.iov_len = ipike.disp.recv_buf_len;
/* Initialize name, io, control and flags */
pi_msg.msg_name = &pi_src;
pi_msg.msg_namelen = sizeof(pi_src);
pi_msg.msg_iov = &pi_vec;
pi_msg.msg_iovlen = 1;
pi_msg.msg_control = (char*)ipike.disp.recv_buf + ipike.disp.recv_buf_len; /* Start of CLEN */
pi_msg.msg_controllen = IPIKE_PKT_CLEN;
pi_msg.msg_flags = 0;
/* Read and process a IKE message */
recv_len = ipcom_recvmsg(socket->fd, &pi_msg, 0);
/* We've gotten something */
if ( recv_len != IP_SOCKERR &&
(pi_msg.msg_flags & (IP_MSG_TRUNC | IP_MSG_CTRUNC)) != 0)
{
IPCOM_LOG0(WARNING, "ipike_receive_message() :: truncated message received -> discarding");
recv_len = 0; /* reset count */
}
#else
addr_len = sizeof(msg->peer_addr);
recv_len = ipcom_recvfrom(socket->fd,
ipike.disp.recv_buf,
ipike.disp.recv_buf_len,
0,
(struct Ip_sockaddr *) &msg->peer_addr,
&addr_len);
#endif /* IPIKE_USE_PKTINFO */
/* Check for receive errors */
if (recv_len == IP_SOCKERR)
{
/* Check for reconfigure notifications */
if ( ipcom_atomic_get(&ipike.disp.reconfigure) )
{
IPCOM_LOG0(DEBUG, "ipike_receive_message() :: "\
"reconfigure notifications received");
/* This reconfigures all listening UDP sockets */
ipike_dispatcher_reconfigure();
ipcom_atomic_set(&ipike.disp.reconfigure, 0);
}
else
{
IPCOM_LOG2(ERR, "ipike_receive_message() :: "\
"failed in to receive (retry %d) (%s)",
retry_count,
ipcom_strerror(ipcom_errno));
if (retry_count == IPIKE_DISPATCHER_RECEIVE_RETRIES)
{
IPCOM_LOG1(ERR, "ipike_receive_message() :: "\
"%d consecutive receive failures"\
" reconfiguring", retry_count);
ipike_dispatcher_reconfigure();
retry_count = 0;
}
else
{
/* Increase retry count and retry again */
retry_count++;
}
}
}
/* Continue until we have received a packet */
} while ( recv_len <= 0 || IP_FD_ISSET(ipike.ipd, &fd_read));
/* Set received length */
msg->data.len = (Ip_size_t) recv_len;
if (IP_NULL == (msg->data.value = ipcom_malloc(msg->data.len)))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
goto cleanup;
}
ipcom_memcpy(msg->data.value, ipike.disp.recv_buf, msg->data.len);
addr_len = sizeof(msg->local_addr);
if (0 > ipcom_getsockname(socket->fd, (struct Ip_sockaddr *) &msg->local_addr, &addr_len))
{
IPCOM_LOG1(ERR, "ipike_receive_message() :: ipcom_getsockname() failed, errno=%d", ipcom_errno);
err = IPIKE_RECEIVE_FAILED;
goto cleanup;
}
#ifdef IPIKE_USE_PKTINFO
/* Setup local and peer address peer address in pi_src and local
* in pktinfo. Since pktinfo doesnt include port number we get it
* using the old mechanism of getsockname
*/
local_port = ipike_addr_get_port(&msg->local_addr);
(void)ipike_addr_copy(&msg->peer_addr,&pi_src);
if (pi_msg.msg_controllen > 0)
{
/* Loop the ancillary data, see what we find */
for (cmsghdr = IP_CMSG_FIRSTHDR(&pi_msg); cmsghdr != 0;
cmsghdr = IP_CMSG_NXTHDR(&pi_msg, cmsghdr))
{
#ifdef IPNET
#ifdef IPCOM_USE_INET
if ((cmsghdr->cmsg_level == IP_IPPROTO_IP) &&
(cmsghdr->cmsg_type == IP_IP_PKTINFO))
{
struct Ip_in_pktinfo *pktinfo = (struct Ip_in_pktinfo *)IP_CMSG_DATA(cmsghdr);
if (pktinfo != IP_NULL)
{
ipike_ip4_addr_to_sockaddr((struct Ip_sockaddr_in*)&msg->local_addr,pktinfo->ipi_addr.s_addr);
}
}
#endif
#ifdef IPCOM_USE_INET6
if ((cmsghdr->cmsg_level == IP_IPPROTO_IPV6)
&& ((cmsghdr->cmsg_type == IP_IPV6_PKTINFO) ||
(cmsghdr->cmsg_type == IP_IPV6_RECVPKTINFO)))
{
struct Ip_in6_pktinfo *pktinfo6 = (struct Ip_in6_pktinfo *)IP_CMSG_DATA(cmsghdr);
if (pktinfo6 != IP_NULL)
{
(void)ipike_ip6_create_sockaddr((struct Ip_sockaddr_in6*)&msg->local_addr,&pktinfo6->ipi6_addr,pktinfo6->ipi6_ifindex);
}
}
#endif
#endif /*#ifdef IPNET */
}
(void)ipike_addr_set_port(&msg->local_addr,local_port);
}
#endif /* IPIKE_USE_PKTINFO */
IPCOM_LOG3(DEBUG, "Received %d octets from %s [%d]",
msg->data.len,
ipike_addr_to_str(&msg->peer_addr),
ipike_addr_get_port(&msg->peer_addr));
IPCOM_LOG2(DEBUG2,"Delivered to addr %s [%d]",
ipike_addr_to_str(&msg->local_addr),
ipike_addr_get_port(&msg->local_addr));
err = IPIKE_SUCCESS;
cleanup:
if (err)
IPIKE_FREEP(msg->data.value);
return err;
}
/*
*===========================================================================
* ipike_send_message
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_send_message(Ipike_message* msg)
{
Ipike_socket * socket = IP_NULL;
#ifdef IPIKE_USE_PKTINFO
#ifdef IPCOM_USE_INET6
Ip_u8 msgbuf[IP_CMSG_SPACE(sizeof(struct Ip_in6_pktinfo))];
#else
Ip_u8 msgbuf[IP_CMSG_SPACE(sizeof(struct Ip_in_pktinfo))];
#endif
struct Ip_iovec pi_vec;
struct Ip_msghdr pi_msg;
struct Ip_cmsghdr *cmsghdr;
#endif
char srcbuf[64];
IPCOM_LOG5(DEBUG, "Send %d octets from %s:%d to %s:%d",
msg->data.len,
ipike_addr_to_str_buf(&msg->local_addr,srcbuf, sizeof(srcbuf)),
ipike_addr_get_port(&msg->local_addr),
ipike_addr_to_str(&msg->peer_addr),
ipike_addr_get_port(&msg->peer_addr));
socket = ipike_dispatcher_socket_get(&msg->local_addr);
if (socket == IP_NULL)
{
IPCOM_LOG2(ERR, "ipike_send_message() :: No socket for %s:%d",
ipike_addr_to_str(&msg->local_addr),
ipike_addr_get_port(&msg->local_addr));
return IPIKE_SEND_FAILED;
}
#ifdef IPIKE_USE_PKTINFO
/* Set buffer data to send */
pi_vec.iov_base = msg->data.value;
pi_vec.iov_len = msg->data.len;
/* Initialize message header */
pi_msg.msg_control = msgbuf;
pi_msg.msg_controllen = sizeof(msgbuf);
pi_msg.msg_name = &msg->peer_addr;
if(msg->peer_addr.sa.sa_family == IP_AF_INET)
{
pi_msg.msg_namelen = sizeof(struct Ip_sockaddr_in);
}
else
{
pi_msg.msg_namelen = sizeof(struct Ip_sockaddr_in6);
}
pi_msg.msg_iov = &pi_vec;
pi_msg.msg_iovlen = 1;
pi_msg.msg_flags = 0;
/* Initialize ancillary message header */
cmsghdr = IP_CMSG_FIRSTHDR(&pi_msg);
/* Set source address information */
switch ( msg->local_addr.sa.sa_family )
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
{
struct Ip_in_pktinfo *pktinfo = (struct Ip_in_pktinfo *)IP_CMSG_DATA(cmsghdr);
pktinfo->ipi_ifindex = 0;
pktinfo->ipi_addr = msg->local_addr.sin.sin_addr;
cmsghdr->cmsg_level = IP_IPPROTO_IP;
cmsghdr->cmsg_type = IP_IP_PKTINFO;
cmsghdr->cmsg_len = IP_CMSG_LEN(sizeof(struct Ip_in_pktinfo));
}
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
{
IP_EXTERN Ip_bool ipnet_ip6_is_link_local_addr(IP_CONST struct Ip_in6_addr* addr);
struct Ip_in6_pktinfo *pktinfo6 = (struct Ip_in6_pktinfo *)IP_CMSG_DATA(cmsghdr);
pktinfo6->ipi6_ifindex = 0;
pktinfo6->ipi6_addr = msg->local_addr.sin6.sin6_addr;
cmsghdr->cmsg_level = IP_IPPROTO_IPV6;
cmsghdr->cmsg_type = IP_IPV6_PKTINFO;
cmsghdr->cmsg_len = IP_CMSG_LEN(sizeof(struct Ip_in6_pktinfo));
if(ipnet_ip6_is_link_local_addr(&pktinfo6->ipi6_addr))
{
pktinfo6->ipi6_ifindex = msg->local_addr.sin6.sin6_scope_id;
}
}
break;
#endif
default:
return IPIKE_SEND_FAILED;
}
/* Update total length */
pi_msg.msg_controllen = cmsghdr->cmsg_len;
/* Send message */
if ( ipcom_sendmsg(socket->fd, &pi_msg, 0) <= 0 )
{
IPCOM_LOG6(ERR, "send %s:%d -> %s:%d on fd %d failed (%s)",
ipike_addr_to_str_buf(&msg->local_addr,srcbuf, sizeof(srcbuf)),
ipike_addr_get_port(&msg->local_addr),
ipike_addr_to_str(&msg->peer_addr),
ipike_addr_get_port(&msg->peer_addr),
socket->fd,
ipcom_strerror(ipcom_errno));
return IPIKE_SEND_FAILED;
}
#else /* IPIKE_USE_PKTINFO */
if((msg->peer_addr.sa.sa_family == IP_AF_INET)
{
if (0 >= ipcom_sendto(socket->fd, msg->data.value, msg->data.len,
0, (struct Ip_sockaddr *) &msg->peer_addr, sizeof(struct Ip_sockaddr_in)))
{
IPCOM_LOG2(ERR, "send to %s failed (%s)",
ipike_addr_to_str(&msg->peer_addr),
ipcom_strerror(ipcom_errno));
return IPIKE_SEND_FAILED;
}
}
else
{
if (0 >= ipcom_sendto(socket->fd, msg->data.value, msg->data.len,
0, (struct Ip_sockaddr *) &msg->peer_addr, sizeof(struct Ip_sockaddr_in6)))
{
IPCOM_LOG2(ERR, "send to %s failed (%s)",
ipike_addr_to_str(&msg->peer_addr),
ipcom_strerror(ipcom_errno));
return IPIKE_SEND_FAILED;
}
}
#endif /* IPIKE_USE_PKTINFO */
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_free_message
*===========================================================================
*/
IP_GLOBAL void
ipike_free_message(Ipike_message* msg)
{
ipcom_free(msg->data.value);
}
/*
*===========================================================================
* ipike_dispatcher_flows_add
*===========================================================================
*/
IP_GLOBAL void
ipike_dispatcher_flows_add(void)
{
Ipike_socket * socket;
/* Bypass flows for UDP sockets */
for ( socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_next(&socket->list))
{
ipike_dispatcher_bypass_flow_add(&socket->addr);
}
/* Trigger flows like 'require' and 'acquire' flows. */
ipike_dispatcher_trigger_flows_add();
}
/*
*===========================================================================
* ipike_dispatch_start_sa_negotiation
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_dispatch_start_sa_negotiation(
Ipike_config_ipsec_sa * exception)
{
Ipike_error err;
int pos = 0;
if (ipike.config.ipsec_sa != IP_NULL)
{
while (ipike.config.ipsec_sa[pos] != IP_NULL)
{
if ( ipike.config.ipsec_sa[pos] != exception &&
ipike.config.ipsec_sa[pos]->ike_sa != IP_NULL &&
!ipike.config.ipsec_sa[pos]->ike_sa->passive &&
!ipike_ipsec_sadb_sa_exist(ipike.config.ipsec_sa[pos]->ipsec_id) &&
!ipike_isakmp_exchange_in_progress(ipike.config.ipsec_sa[pos]->ipsec_id))
{
/* Non-passive and no IKE SA -> start IKE negotiation */
err = ipike_isakmp_add_ipsec_negotiation(ipike.config.ipsec_sa[pos],
IP_NULL,
IP_NULL,
IP_NULL);
/* Report error but ignore, since IPIKE should be fail safe,
* but stop if too many exchanges. */
if (IPIKE_SUCCESS != err)
IPCOM_LOG1(ERR, "ipike_dispatch_start_sa_negotiation() ::"\
" failed to start IPSec negotiation (%s)",
ipike.config.ipsec_sa[pos]->ipsec_id);
if (IPIKE_TOO_MANY_EXCHANGES == err)
break;
}
pos++;
}
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_dispatch_add_radius_socket
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_dispatch_add_radius_socket(Ip_fd sock)
{
#ifdef IPIKE_USE_RADIUS
Ip_u32 i;
if (ipike.disp.sock_radius_count == ipike.disp.sock_radius_count_max)
{
/* Increase the number of radius sockets by 4 each time,
* we don't expect many sockets */
i = ipike.disp.sock_radius_count_max + 4;
ipike.disp.sock_radius = ipcom_realloc(ipike.disp.sock_radius, i*sizeof(*ipike.disp.sock_radius));
if (ipike.disp.sock_radius == IP_NULL)
{
IP_PANIC();
ipike.disp.sock_radius_count = 0;
ipike.disp.sock_radius_count_max = 0;
return IPIKE_OUT_OF_MEMORY;
}
ipike.disp.sock_radius_count_max = i;
}
if (ipike.disp.sock_radius_count < ipike.disp.sock_radius_count_max)
ipike.disp.sock_radius[ipike.disp.sock_radius_count++] = sock;
#else
(void)sock; /* lint */
#endif
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_dispatch_remove_radius_socket
*===========================================================================
*/
IP_GLOBAL void
ipike_dispatch_remove_radius_socket(Ip_fd sock)
{
#ifdef IPIKE_USE_RADIUS
Ip_u32 i;
for (i=0; i < ipike.disp.sock_radius_count; i++)
{
if (ipike.disp.sock_radius[i] == sock)
{
ipike.disp.sock_radius_count--;
for (; i < ipike.disp.sock_radius_count; i++)
ipike.disp.sock_radius[i] = ipike.disp.sock_radius[i+1];
ipike.disp.sock_radius[i] = IP_INVALID_SOCKET;
}
}
#else
(void)sock; /* lint */
#endif
return;
}
/*
*===========================================================================
* ipike_dispatch_remove_all_radius_sockets
*===========================================================================
*/
IP_GLOBAL void
ipike_dispatch_remove_all_radius_sockets(void)
{
#ifdef IPIKE_USE_RADIUS
Ip_u32 i = 0;
for (i=0; i < ipike.disp.sock_radius_count; i++)
ipcom_socketclose(ipike.disp.sock_radius[i]);
ipcom_free(ipike.disp.sock_radius);
ipike.disp.sock_radius = IP_NULL;
ipike.disp.sock_radius_count_max = 0;
ipike.disp.sock_radius_count = 0;
#endif
return;
}
/*
*===========================================================================
* ipike_dispatch_enum_radius_socket
*===========================================================================
*/
IP_GLOBAL Ip_fd
ipike_dispatch_enum_radius_socket(Ip_u32* last)
{
#ifdef IPIKE_USE_RADIUS
if (*last < ipike.disp.sock_radius_count)
return ipike.disp.sock_radius[(*last)++];
#else
(void)last; /* lint */
#endif
return IP_INVALID_SOCKET;
}
/*
*===========================================================================
* ipike_dispath_open_cmd_socket
*===========================================================================
*/
IP_GLOBAL Ip_fd
ipike_dispath_open_cmd_socket(Ip_bool listen)
{
Ip_fd fd = IP_INVALID_SOCKET;
char port[8];
struct Ip_addrinfo hints;
struct Ip_addrinfo *res = IP_NULL;
struct Ip_linger linger;
/* Create the shell command socket */
ipcom_memset(&hints, 0, sizeof(hints));
hints.ai_socktype = IP_SOCK_STREAM;
hints.ai_flags = IP_AI_NUMERICHOST;
hints.ai_family = IP_AF_UNSPEC;
ipcom_sprintf(port, "%d", ipcom_sysvar_get_as_int("ipike.port", 500));
if (ipcom_getaddrinfo(IP_NULL, port, &hints, &res) != 0)
{
IPCOM_LOG0(DEBUG, "ipike_dispath_open_cmd_socket: failed to get address info");
}
else
{
fd = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (fd == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR,
"ipike_dispath_open_cmd_socket: failed to create socket: %s",
ipcom_strerror(ipcom_errno));
}
else
{
if (listen)
{
if (ipcom_bind(fd, res->ai_addr, (Ip_socklen_t)res->ai_addrlen) < 0)
{
IPCOM_LOG2(ERR,
"ipike_dispath_open_cmd_socket: failed to bind address %s to socket: %s",
ipike_addr_to_str((union Ip_sockaddr_union *) res->ai_addr),
ipcom_strerror(ipcom_errno));
ipcom_socketclose(fd);
fd = IP_INVALID_SOCKET;
}
else if (ipcom_listen(fd, 0) < 0)
{
IPCOM_LOG1(ERR,
"ipike_dispath_open_cmd_socket: failed to listen on socket: %s",
ipcom_strerror(ipcom_errno));
ipcom_socketclose(fd);
fd = IP_INVALID_SOCKET;
}
}
else
{
linger.l_onoff = 1;
linger.l_linger = 0;
(void)ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_LINGER, &linger, sizeof(linger));
if (ipcom_connect(fd, res->ai_addr, (Ip_socklen_t)res->ai_addrlen) < 0)
{
IPCOM_LOG1(ERR,
"ipike_dispath_open_cmd_socket: failed to connect shell command socket: %s",
ipcom_strerror(ipcom_errno));
ipcom_socketclose(fd);
fd = IP_INVALID_SOCKET;
}
}
}
ipcom_freeaddrinfo(res);
}
return fd;
}
/*
*===========================================================================
* ipike_dispatch_commit_address_update
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_dispatch_commit_address_update(struct Ipike_sadb_entry_struct *ike_sa)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_config_ike_sa *conf = IP_NULL;
Ip_u32 i = 0;
const char *str = IP_NULL;
/* Update IPSec SADB */
if (IPIKE_SUCCESS != (err = ipike_ipsec_sadb_update_addresses(ike_sa)))
{
IPCOM_LOG0(ERR, "ipike_dispatch_commit_address_update() ::"\
" update IPSec SADB failed");
return err;
}
/* Update configuration */
conf = ipike_config_get_ike_sa_from_id(ipike.config.ike_sa, ike_sa->id);
if ( conf == IP_NULL )
{
IPCOM_LOG0(ERR, "ipike_dispatch_commit_address_update() ::"\
" update IPSec SADB failed");
return IPIKE_CONF_VALUE_NOT_FOUND;
}
/* Is local address updated? */
if (ipike_addr_is_valid(&ike_sa->mobike.update.local_addr))
{
if (ipike_addr_compare(&conf->local_address,
&ike_sa->local_addr) == 0)
{
(void)ipike_addr_copy(&conf->local_address,
&ike_sa->mobike.update.local_addr);
(void)ipike_addr_set_port(&conf->local_address, ipike.port);
if ((conf->local_id != IP_NULL) &&
(ipcom_strncmp(conf->local_id, "address ", 8) == 0))
{
str = ipike_addr_to_str(&conf->local_address);
ipcom_free((void*)conf->local_id);
if (IP_NULL != (conf->local_id = ipcom_malloc(9+ipcom_strlen(str))))
ipcom_sprintf((char*)conf->local_id, "address %s", str);
}
}
while (ipike.config.general.listen[i] != IP_NULL)
{
if (ipike_addr_compare(ipike.config.general.listen[i],
&ike_sa->local_addr) == 0)
(void)ipike_addr_copy(ipike.config.general.listen[i],
&ike_sa->mobike.update.local_addr);
i++;
}
}
/* Is peer address updated? */
if (ike_sa->mobike.update.peer_addr.sa.sa_family != 0)
{
if (ipike_addr_compare(&conf->remote_address.addr, &ike_sa->peer_addr) == 0)
{
(void)ipike_addr_copy(&conf->remote_address.addr,
&ike_sa->mobike.update.peer_addr);
(void)ipike_addr_set_port(&conf->remote_address.addr, ipike.port);
}
}
/* Update IKE SADB */
err = ipike_sadb_update_address(ike_sa,
&ike_sa->mobike.update.local_addr,
&ike_sa->mobike.update.peer_addr);
if (IPIKE_SUCCESS != err )
{
IPCOM_LOG0(ERR, "ipike_dispatch_commit_address_update() ::"\
" update IKE SADB failed");
}
return err;
}
/*
*===========================================================================
* ipike_dispath_handle_ipd_command
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_dispath_handle_ipd_command(Ip_u8 cmd, Ip_fd fd, Ip_u8* buf, Ip_u32 len)
{
Ipike_error err = IPIKE_FAILED;
/* */
switch (cmd)
{
case IPIKE_CMD_MOBIKE:
err = ipike_shell_cmd_mobike(fd, buf, len);
break;
case IPIKE_CMD_LIST:
case IPIKE_CMD_STAT:
case IPIKE_CMD_CONFIG_DUMP:
case IPIKE_CMD_CONFIG_LOAD:
case IPIKE_CMD_CONFIG_ADD:
case IPIKE_CMD_CONFIG_DELETE:
/* Currently no support to call from IPD socket */
err = IPIKE_FAILED;
break;
}
return err;
}
/*
*===========================================================================
* ipike_dispatcher_startup
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_dispatcher_startup(void)
{
Ipike_error err = IPIKE_SUCCESS;
if (ipike.disp.initialized)
ipike_dispatcher_shutdown();
ipike.disp.initialized = IP_TRUE;
ipcom_list_init(&ipike.disp.sockets);
ipcom_list_init(&ipike.disp.flowtype_flows);
ipcom_atomic_set(&ipike.disp.reconfigure, 0);
/* Start listen on all specified addresses in configuration */
ipike_dispatcher_reconfigure();
/* Open IKE shell socket */
ipike.disp.shell_cmd_sock = ipike_dispath_open_cmd_socket(IP_TRUE);
if (ipike.disp.shell_cmd_sock == IP_INVALID_SOCKET)
{
IPCOM_LOG0(ERR, "ipike_dispatcher_startup: failed to open shell command socket");
goto cleanup;
}
/* Init periodical timer */
ipike.disp.ticks = 0;
err = IPIKE_OUT_OF_MEMORY;
if (ipcom_tmo2_request(ipike.tmo_head,
&ipike.housekeep_tmo,
ipike_dispatch_housekeeping_tmo_cb,
IP_NULL,
1000) != IPCOM_SUCCESS)
goto cleanup;
/* Mallocate IKE receive buffer */
ipike.disp.recv_buf_len = (Ip_size_t) ipcom_sysvar_get_as_int("ipike.isakmp_sock_buf_size", 10000);
ipike.disp.recv_buf = ipcom_malloc(ipike.disp.recv_buf_len + IPIKE_PKT_CLEN);
if (ipike.disp.recv_buf != IP_NULL)
err = IPIKE_SUCCESS;
cleanup:
if (err != IPIKE_SUCCESS)
ipike_dispatcher_shutdown();
return err;
}
/*
*===========================================================================
* ipike_dispatcher_shutdown
*===========================================================================
*/
IP_GLOBAL void
ipike_dispatcher_shutdown(void)
{
if (ipike.disp.initialized == IP_FALSE)
return;
ipike.disp.initialized = IP_FALSE;
/* Free receive buffer */
ipcom_free(ipike.disp.recv_buf);
ipike.disp.recv_buf = IP_NULL;
ipike.disp.recv_buf_len = 0;
ipike_tmo2_cancel(&ipike.housekeep_tmo);
/* Close IKE daemon sockets, this will also remove the corresponding
* bypass flows */
ipike_dispatcher_destroy_sockets();
ipike_dispatch_remove_all_radius_sockets();
ipike_http_fetcher_cleanup();
/* Delete all IPSec flows with flow types set (acquire/require) */
ipike_dispatcher_trigger_flows_remove();
/* Close IKE shell socket */
ipcom_socketclose(ipike.disp.shell_cmd_sock);
ipike.disp.shell_cmd_sock = IP_INVALID_SOCKET;
/* Make sure we don't have any lingering flows or sockets */
ip_assert(ipcom_list_first(&ipike.disp.sockets) == IP_NULL);
ip_assert(ipcom_list_first(&ipike.disp.flowtype_flows) == IP_NULL);
}
/*
*===========================================================================
* ipike_dispatcher_reconfigure
*===========================================================================
*/
IP_GLOBAL void
ipike_dispatcher_reconfigure(void)
{
int i = 0;
IPIKE_CODE_LOCK();
/* Only let the IKE reconfigure it's sockets */
if (ipike.pid == ipcom_getpid())
{
/* Destroy and close all listening sockets */
ipike_dispatcher_destroy_sockets();
/* Start listen on the addresses in the configuration */
if ( ipike.config.general.listen != IP_NULL )
{
for ( i = 0;
ipike.config.general.listen[i] != IP_NULL;
i++)
{
(void)ipike_dispatcher_start_listen(ipike.config.general.listen[i]);
}
}
ipike_dispatcher_trigger_flows_add();
}
else
{
/* Notify the IKE daemon to reconfigure itself */
ipike_dispatcher_reconfigure_notify();
}
IPIKE_CODE_UNLOCK();
}
/*
*===========================================================================
* ipike_dispatcher_socket_local_addr_get
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_dispatcher_socket_local_addr_get(
union Ip_sockaddr_union* local,
union Ip_sockaddr_union* remote)
{
Ipike_socket * socket = IP_NULL;
Ipike_error err = IPIKE_FAILED;
/* Make any address of correct family */
(void)ipike_addr_copy(local, remote);
ipcom_memset(ipike_addr_get_ptr(local), 0, ipike_addr_get_len(local));
for (socket = (Ipike_socket *) ipcom_list_first(&ipike.disp.sockets);
socket != IP_NULL;
socket = (Ipike_socket *) ipcom_list_next(&socket->list))
{
if (ipike_addr_match_socket(local, socket->fd))
{
/* We found a suitable socket */
union Ip_sockaddr_union sock_addr;
Ip_socklen_t namelen = sizeof(sock_addr);
/* Connect the socket to the destination */
if (ipcom_connect(socket->fd, &remote->sa, sizeof(*remote)) < 0)
{
IPCOM_LOG1(ERR,
"ipike_dispatcher_socket_local_addr_get() :: "
"connect failed, %s",
ipcom_strerror(ipcom_errno));
return IPIKE_FAILED;
}
/* Get socket address */
if (ipcom_getsockname(socket->fd, &sock_addr.sa, &namelen) < 0)
{
IPCOM_LOG1(ERR,
"ipike_dispatcher_socket_local_addr_get() :: "
"failed to get socket address, %s",
ipcom_strerror(ipcom_errno));
err = IPIKE_FAILED;
}
else
{
IPCOM_LOG1(DEBUG,
"ipike_dispatcher_socket_local_addr_get() :: "\
"using local address %s",
ipike_addr_to_str(&sock_addr));
(void)ipike_addr_copy(local, &sock_addr);
err = IPIKE_SUCCESS;
}
ipcom_memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sa.sa_family = IP_AF_UNSPEC;
/* "Unconnect" the socket again */
if (ipcom_connect(socket->fd, &sock_addr.sa, sizeof(sock_addr)) < 0)
{
IPCOM_LOG1(ERR,
"ipike_dispatcher_socket_local_addr_get() :: "
"unconnect failed, %s",
ipcom_strerror(ipcom_errno));
return IPIKE_FAILED;
}
return err;
}
}
return IPIKE_FAILED;
}
/*
*===========================================================================
* ipike_mobike_handler
*===========================================================================
* Make shell command obsolete ( !!FIXME: delete shell cmd )
*/
#ifdef IPIKE_USE_MIGRATE
IP_GLOBAL Ipike_error
ipike_mobike_handler(
union Ip_sockaddr_union * old_addr,
union Ip_sockaddr_union * new_addr)
{
Ipike_error err = IPIKE_SUCCESS;
IPIKE_CODE_LOCK();
ipike_addr_set_port(old_addr, ipike.port);
ipike_addr_set_port(new_addr, ipike.port);
if (ipike_addr_compare(old_addr, new_addr) == 0)
{
IPCOM_LOG0(ERR, "Bad new ip address, same sa old.");
err = IPIKE_MOBIKE_SIMILAR_ADDRESS;
}
else
{
(void)ipike_dispatcher_stop_listen(old_addr);
if (ipike_dispatcher_socket_get(new_addr) == IP_NULL &&
ipike_dispatcher_start_listen(new_addr) != IPIKE_SUCCESS)
{
(void)ipike_dispatcher_start_listen(old_addr);
IPCOM_LOG0(ERR, "Failed to start listen on new ip address.");
err = IPIKE_MOBIKE_LISTEN_NEW_FAILED;
}
else if (ipike_sadb_initiate_address_update(old_addr, new_addr) != IPIKE_SUCCESS)
{
(void)ipike_dispatcher_stop_listen(new_addr);
(void)ipike_dispatcher_start_listen(old_addr);
IPCOM_LOG0(ERR, "Failed to initiate address update.");
err = IPIKE_MOBIKE_UPDATE_FAILED;
}
else
{
IPCOM_LOG0(DEBUG,"Address update initiated.");
err = IPIKE_MOBIKE_UPDATE_INITIATED;
}
}
IPIKE_CODE_UNLOCK();
/* Send response back to MIP */
return ipike_pfkeyv2_send_migrate_resp(err, old_addr, new_addr);
}
#endif /* IPIKE_USE_MIGRATE */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/