2779 lines
87 KiB
C
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
|
|
****************************************************************************
|
|
*/
|