/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 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 #include #include #include /* **************************************************************************** * 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: " " */ 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 **************************************************************************** */