From bba65f4a1e59061107432a107228811b6f979b04 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 26 Mar 2008 22:14:09 +0000 Subject: [PATCH] add acl stuff git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@7966 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- conf/autoload_configs/event_socket.conf.xml | 1 + conf/sip_profiles/default.xml | 2 + src/include/switch_apr.h | 2 +- src/include/switch_core.h | 2 + src/include/switch_types.h | 3 + src/include/switch_utils.h | 9 ++ .../applications/mod_commands/mod_commands.c | 59 ++++++++ .../applications/mod_dptools/mod_dptools.c | 24 ++++ src/mod/endpoints/mod_sofia/mod_sofia.h | 7 + src/mod/endpoints/mod_sofia/sofia.c | 24 ++++ src/mod/endpoints/mod_sofia/sofia_reg.c | 17 +++ .../mod_event_socket/mod_event_socket.c | 50 ++++++- src/switch_apr.c | 5 + src/switch_core.c | 130 ++++++++++++++++- src/switch_utils.c | 132 ++++++++++++++++++ 15 files changed, 464 insertions(+), 3 deletions(-) diff --git a/conf/autoload_configs/event_socket.conf.xml b/conf/autoload_configs/event_socket.conf.xml index ea9a0b9ba7..98a2764d0f 100644 --- a/conf/autoload_configs/event_socket.conf.xml +++ b/conf/autoload_configs/event_socket.conf.xml @@ -3,5 +3,6 @@ + diff --git a/conf/sip_profiles/default.xml b/conf/sip_profiles/default.xml index 5a8bdb44e5..648a8acef6 100644 --- a/conf/sip_profiles/default.xml +++ b/conf/sip_profiles/default.xml @@ -29,6 +29,8 @@ + + diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index 5a5cbd3fe8..8bc1f9abf5 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -1232,7 +1232,7 @@ SWITCH_DECLARE(switch_status_t) switch_poll(switch_pollfd_t * aprset, int32_t nu SWITCH_DECLARE(switch_status_t) switch_socket_create_pollfd(switch_pollfd_t ** poll, switch_socket_t * sock, int16_t flags, switch_memory_pool_t *pool); SWITCH_DECLARE(switch_status_t) switch_match_glob(const char *pattern, switch_array_header_t **result, switch_memory_pool_t *p); - +SWITCH_DECLARE(switch_status_t) switch_socket_addr_get(switch_sockaddr_t **sa, switch_bool_t remote, switch_socket_t *sock); /** @} */ diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 1762b53540..ce57eef43f 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1591,6 +1591,8 @@ SWITCH_DECLARE(void) switch_core_memory_reclaim_all(void); SWITCH_DECLARE(void) switch_core_setrlimits(void); SWITCH_DECLARE(void) switch_time_sync(void); SWITCH_DECLARE(time_t) switch_timestamp(time_t *t); +SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload); +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip(const char *ip_str, const char *list_name); ///\} diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 31a3a0917a..d8244ce278 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1259,6 +1259,9 @@ typedef struct switch_hash switch_hash_t; struct HashElem; typedef struct HashElem switch_hash_index_t; +struct switch_network_list; +typedef struct switch_network_list switch_network_list_t; + #define SWITCH_API_VERSION 1 #define SWITCH_MODULE_LOAD_ARGS (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 52c20937e6..7e50bef89a 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -84,6 +84,7 @@ SWITCH_DECLARE(switch_size_t) switch_fd_read_line(int fd, char *buf, switch_size !strcasecmp(expr, "true") ||\ !strcasecmp(expr, "enabled") ||\ !strcasecmp(expr, "active") ||\ +!strcasecmp(expr, "allow") ||\ atoi(expr))) ? SWITCH_TRUE : SWITCH_FALSE /*! \brief find local ip of the box @@ -347,6 +348,14 @@ SWITCH_DECLARE(char *) switch_url_decode(char *s); SWITCH_DECLARE(switch_bool_t) switch_simple_email(const char *to, const char *from, const char *headers, const char *body, const char *file); SWITCH_DECLARE(char *) switch_find_end_paren(const char *s, char open, char close); +SWITCH_DECLARE(int) switch_parse_cidr(const char *string, uint32_t *ip, uint32_t *mask, uint32_t *bitp); +SWITCH_DECLARE(switch_status_t) switch_network_list_create(switch_network_list_t **list, switch_bool_t default_type, switch_memory_pool_t *pool); +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok); +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok); +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip(switch_network_list_t *list, uint32_t ip); +#define switch_test_subnet(_ip, _net, _mask) (_mask ? ((_net & _mask) == (_ip & _mask)) : _net == _ip) + + /* malloc or DIE macros */ #ifdef NDEBUG #define switch_malloc(ptr, len) (void)( (!!(ptr = malloc(len))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%s", __FILE__, __LINE__),abort(), 0), ptr ) diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index e2178fe966..872896bc94 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -271,6 +271,63 @@ end: return SWITCH_STATUS_SUCCESS; } +SWITCH_STANDARD_API(reload_acl_function) +{ + const char *err; + switch_xml_t xml_root; + + if (session) { + return SWITCH_STATUS_FALSE; + } + + if (cmd && !strcmp(cmd, "reloadxml")) { + if ((xml_root = switch_xml_open_root(1, &err))) { + switch_xml_free(xml_root); + } + } + + switch_load_network_lists(SWITCH_TRUE); + + stream->write_function(stream, "+OK acl reloaded\n"); + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_API(acl_function) +{ + int argc; + char *mydata = NULL, *argv[3]; + + if (!cmd) { + goto error; + } + + mydata = strdup(cmd); + switch_assert(mydata); + + argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc < 2) { + goto error; + } + + if (switch_check_network_list_ip(argv[0], argv[1])) { + stream->write_function(stream, "true"); + goto ok; + } + +error: + + stream->write_function(stream, "false"); + +ok: + + switch_safe_free(mydata); + + return SWITCH_STATUS_SUCCESS; + +} + + SWITCH_STANDARD_API(regex_function) { switch_regex_t *re = NULL; @@ -2186,6 +2243,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "killchan", "Kill Channel (depricated)", kill_function, KILL_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill Channel", kill_function, KILL_SYNTAX); SWITCH_ADD_API(commands_api_interface, "uuid_park", "Park Channel", park_function, PARK_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "[reloadxml]"); SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_function, ""); SWITCH_ADD_API(commands_api_interface, "unload", "Unload Module", unload_function, LOAD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "load", "Load Module", load_function, LOAD_SYNTAX); @@ -2226,6 +2284,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "is_lan_addr", "see if an ip is a lan addr", lan_addr_function, ""); SWITCH_ADD_API(commands_api_interface, "cond", "Eval a conditional", cond_function, " ? : "); SWITCH_ADD_API(commands_api_interface, "regex", "Eval a regex", regex_function, "|[|]"); + SWITCH_ADD_API(commands_api_interface, "acl", "compater an ip to an acl list", acl_function, " "); SWITCH_ADD_API(commands_api_interface, "uuid_chat", "Send a chat message", uuid_chat, UUID_CHAT_SYNTAX); SWITCH_ADD_API(commands_api_interface, "find_user_xml", "find a user", find_user_function, " "); SWITCH_ADD_API(commands_api_interface, "user_exists", "find a user", user_exists_function, " "); diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 10588115c3..8b3b35aa6c 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -200,6 +200,28 @@ SWITCH_STANDARD_APP(send_dtmf_function) switch_core_session_send_dtmf_string(session, (const char *) data); } +SWITCH_STANDARD_APP(check_acl_function) +{ + int argc; + char *argv[2] = { 0 }; + char *mydata; + switch_call_cause_t cause = SWITCH_CAUSE_CALL_REJECTED; + + if (!switch_strlen_zero(data) && (mydata = switch_core_session_strdup(session, data))) { + if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) > 1) { + if (!switch_check_network_list_ip(argv[0], argv[1])) { + switch_channel_t *channel = switch_core_session_get_channel(session); + if (argc > 2) { + cause = switch_channel_str2cause(argv[2]); + } + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call failed acl check for ip %s on list %s\n", argv[0], argv[1]); + switch_channel_hangup(channel, cause); + } + } + } + +} + SWITCH_STANDARD_APP(transfer_function) { int argc; @@ -1760,6 +1782,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_API(api_interface, "presence", "presence", presence_api_function, " "); SWITCH_ADD_APP(app_interface, "privacy", "Set privacy on calls", "Set caller privacy on calls.", privacy_function, "off|on|name|full|number", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "transfer", "Transfer a channel", TRANSFER_LONG_DESC, transfer_function, " [ ]", SAF_SUPPORT_NOMEDIA); + SWITCH_ADD_APP(app_interface, "check_acl", "Check an ip against an ACL list", + "Check an ip against an ACL list", check_acl_function, " ", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "sleep", "Pause a channel", SLEEP_LONG_DESC, sleep_function, "", SAF_SUPPORT_NOMEDIA); SWITCH_ADD_APP(app_interface, "delay_echo", "echo audio at a specified delay", "Delay n ms", delay_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "strftime", NULL, NULL, strftime_function, NULL, SAF_SUPPORT_NOMEDIA); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index e053181974..ba35159750 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -46,6 +46,8 @@ #include #endif +#define SOFIA_MAX_ACL 100 + #define MODNAME "mod_sofia" static const switch_state_handler_table_t noop_state_handler = { 0 }; struct sofia_gateway; @@ -308,6 +310,11 @@ struct sofia_profile { char *odbc_pass; switch_odbc_handle_t *master_odbc; switch_queue_t *sql_queue; + char *acl[SOFIA_MAX_ACL]; + uint32_t acl_count; + char *reg_acl[SOFIA_MAX_ACL]; + uint32_t reg_acl_count; + }; struct private_object { diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 1a2a1117d4..6911923b3d 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -1195,6 +1195,18 @@ switch_status_t config_sofia(int reload, char *profile_name) profile->username = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "context")) { profile->context = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "apply-inbound-acl")) { + if (profile->acl_count < SOFIA_MAX_ACL) { + profile->acl[profile->acl_count++] = switch_core_strdup(profile->pool, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); + } + } else if (!strcasecmp(var, "apply-register-acl")) { + if (profile->reg_acl_count < SOFIA_MAX_ACL) { + profile->reg_acl[profile->reg_acl_count++] = switch_core_strdup(profile->pool, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SOFIA_MAX_ACL); + } } else if (!strcasecmp(var, "alias")) { sip_alias_node_t *node; if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) { @@ -2478,6 +2490,18 @@ void sofia_handle_sip_i_invite(nua_t *nua, sofia_profile_t *profile, nua_handle_ get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) my_addrinfo->ai_addr)->sin_addr); + if (profile->acl_count) { + int x = 0; + for (x = 0 ; x < profile->acl_count; x++) { + if (!switch_check_network_list_ip(network_ip, profile->acl[x])) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl %s\n", network_ip, profile->acl[x]); + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + return; + } + } + } + + if ((profile->pflags & PFLAG_AUTH_CALLS) || (!(profile->pflags & PFLAG_BLIND_AUTH) && (sip->sip_proxy_authorization || sip->sip_authorization))) { if (strcmp(network_ip, profile->sipip)) { if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key), &v_event)) { diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index e164526a34..3c40b38dde 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -655,6 +655,23 @@ void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t *profile, nua_ { char key[128] = ""; switch_event_t *v_event = NULL; + char network_ip[80]; + su_addrinfo_t *my_addrinfo = msg_addrinfo(nua_current_request(nua)); + + if (profile->reg_acl_count) { + int x = 0; + + get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) my_addrinfo->ai_addr)->sin_addr); + + for (x = 0 ; x < profile->reg_acl_count; x++) { + if (!switch_check_network_list_ip(network_ip, profile->reg_acl[x])) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl %s\n", network_ip, profile->reg_acl[x]); + nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END()); + goto end; + } + } + } + if (!(profile->mflags & MFLAG_REGISTER)) { nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END()); diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index 34988c8b20..b5591af788 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -71,6 +71,9 @@ struct listener { switch_core_session_t *session; int lost_events; int lost_logs; + switch_sockaddr_t *sa; + char remote_ip[50]; + switch_port_t remote_port; struct listener *next; }; @@ -84,6 +87,8 @@ static struct { uint8_t ready; } listen_list; +#define MAX_ACL 100 + static struct { switch_mutex_t *mutex; char *ip; @@ -91,6 +96,8 @@ static struct { char *password; int done; int threads; + char *acl[MAX_ACL]; + uint32_t acl_count; } prefs; SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, prefs.ip); @@ -1052,18 +1059,44 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t * thread, void *obj switch_core_session_t *session = NULL; switch_channel_t *channel = NULL; + switch_mutex_lock(listen_list.mutex); prefs.threads++; switch_mutex_unlock(listen_list.mutex); switch_assert(listener != NULL); + if (prefs.acl_count && listener->sa && !switch_strlen_zero(listener->remote_ip)) { + int x = 0; + + for (x = 0 ; x < prefs.acl_count; x++) { + if (!switch_check_network_list_ip(listener->remote_ip, prefs.acl[x])) { + const char message[] = "Access Denied, go away.\n"; + int mlen = strlen(message); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl %s\n", listener->remote_ip, prefs.acl[x]); + + switch_snprintf(buf, sizeof(buf), "Content-Type: rude/rejection\nContent-Length %d\n\n", mlen); + len = strlen(buf); + switch_socket_send(listener->sock, buf, &len); + len = mlen; + switch_socket_send(listener->sock, message, &len); + goto done; + } + } + } + + if ((session = listener->session)) { channel = switch_core_session_get_channel(session); switch_core_session_read_lock(session); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open\n"); + if (switch_strlen_zero(listener->remote_ip)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open from %s:%d\n", listener->remote_ip, listener->remote_port); + } switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE); switch_set_flag_locked(listener, LFLAG_RUNNING); @@ -1230,6 +1263,12 @@ static int config(void) prefs.port = (uint16_t) atoi(val); } else if (!strcmp(var, "password")) { set_pref_pass(val); + } else if (!strcasecmp(var, "apply-inbound-acl")) { + if (prefs.acl_count < MAX_ACL) { + prefs.acl[prefs.acl_count++] = strdup(val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", MAX_ACL); + } } } } @@ -1259,6 +1298,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime) switch_sockaddr_t *sa; switch_socket_t *inbound_socket = NULL; listener_t *listener; + int x = 0; memset(&listen_list, 0, sizeof(listen_list)); config(); @@ -1335,6 +1375,9 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime) listener->format = EVENT_FORMAT_PLAIN; switch_mutex_init(&listener->flag_mutex, SWITCH_MUTEX_NESTED, listener->pool); switch_core_hash_init(&listener->event_hash, listener->pool); + switch_socket_addr_get(&listener->sa, SWITCH_TRUE, listener->sock); + switch_get_addr(listener->remote_ip, sizeof(listener->remote_ip), listener->sa); + listener->remote_port = switch_sockaddr_get_port(listener->sa); launch_listener_thread(listener); } @@ -1349,6 +1392,11 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_event_socket_runtime) switch_core_destroy_memory_pool(&listener_pool); } + + for (x = 0 ; x < prefs.acl_count; x++) { + switch_safe_free(prefs.acl[x]); + } + fail: return SWITCH_STATUS_TERM; } diff --git a/src/switch_apr.c b/src/switch_apr.c index 57863cd974..82764b17ec 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -521,6 +521,11 @@ SWITCH_DECLARE(switch_status_t) switch_thread_create(switch_thread_t ** new_thre /* socket stubs */ +SWITCH_DECLARE(switch_status_t) switch_socket_addr_get(switch_sockaddr_t **sa, switch_bool_t remote, switch_socket_t *sock) +{ + return apr_socket_addr_get(sa, remote, sock); +} + SWITCH_DECLARE(switch_status_t) switch_socket_create(switch_socket_t ** new_sock, int family, int type, int protocol, switch_memory_pool_t *pool) { return apr_socket_create(new_sock, family, type, protocol, pool); diff --git a/src/switch_core.c b/src/switch_core.c index 8bf6f3813b..167085a0a1 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -686,6 +686,132 @@ SWITCH_DECLARE(void) switch_core_setrlimits(void) return; } +typedef struct { + switch_memory_pool_t *pool; + switch_hash_t *hash; +} switch_ip_list_t; + +static switch_ip_list_t IP_LIST = { 0 }; + +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip(const char *ip_str, const char *list_name) +{ + switch_network_list_t *list; + uint32_t ip, net, mask, bits; + switch_bool_t ok = SWITCH_FALSE; + + switch_mutex_lock(runtime.global_mutex); + inet_pton(AF_INET, ip_str, &ip); + + if ((list = switch_core_hash_find(IP_LIST.hash, list_name))) { + ok = switch_network_list_validate_ip(list, ip); + } else if (strchr(list_name, '/')) { + switch_parse_cidr(list_name, &net, &mask, &bits); + ok = switch_test_subnet(ip, net, mask); + } + switch_mutex_unlock(runtime.global_mutex); + + return ok; +} + + +SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) +{ + switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, x_node = NULL, cfg = NULL; + switch_network_list_t *list; + + + switch_mutex_lock(runtime.global_mutex); + + if (IP_LIST.hash) { + switch_core_hash_destroy(&IP_LIST.hash); + } + + if (IP_LIST.pool) { + switch_core_destroy_memory_pool(&IP_LIST.pool); + } + + memset(&IP_LIST, 0, sizeof(IP_LIST)); + switch_core_new_memory_pool(&IP_LIST.pool); + switch_core_hash_init(&IP_LIST.hash, IP_LIST.pool); + + if ((xml = switch_xml_open_cfg("acl.conf", &cfg, NULL))) { + if ((x_lists = switch_xml_child(cfg, "network-lists"))) { + for (x_list = switch_xml_child(x_lists, "list"); x_list; x_list = x_list->next) { + const char *name = switch_xml_attr(x_list, "name"); + const char *dft = switch_xml_attr(x_list, "default"); + switch_bool_t default_type = SWITCH_TRUE; + + if (switch_strlen_zero(name)) { + continue; + } + + if (dft) { + default_type = switch_true(dft); + } + + if (switch_network_list_create(&list, default_type, IP_LIST.pool) != SWITCH_STATUS_SUCCESS) { + abort(); + } + + if (reload) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Created ip list %s default (%s)\n", name, default_type ? "allow" : "deny"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Created ip list %s default (%s)\n", name, default_type ? "allow" : "deny"); + } + + + for (x_node = switch_xml_child(x_list, "node"); x_node; x_node = x_node->next) { + const char *cidr = NULL, *host = NULL, *mask = NULL; + switch_bool_t ok = default_type; + const char *type = switch_xml_attr(x_node, "type"); + + if (type) { + ok = switch_true(type); + } + + cidr = switch_xml_attr(x_node, "cidr"); + host = switch_xml_attr(x_node, "host"); + mask = switch_xml_attr(x_node, "mask"); + + if (cidr) { + if (switch_network_list_add_cidr(list, cidr, ok) == SWITCH_STATUS_SUCCESS) { + if (reload) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding %s (%s) to list %s\n", cidr, ok ? "allow" : "deny", name); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Adding %s (%s) to list %s\n", cidr, ok ? "allow" : "deny", name); + } + } else { + if (reload) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Error Adding %s (%s) to list %s\n", cidr, ok ? "allow" : "deny", name); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "Error Adding %s (%s) to list %s\n", cidr, ok ? "allow" : "deny", name); + } + } + } else if (host && mask) { + if (switch_network_list_add_host_mask(list, host, mask, ok) == SWITCH_STATUS_SUCCESS) { + if (reload) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, + "Adding %s/%s (%s) to list %s\n", host, mask, ok ? "allow" : "deny", name); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, + "Adding %s/%s (%s) to list %s\n", host, mask, ok ? "allow" : "deny", name); + } + } + } + + switch_core_hash_insert(IP_LIST.hash, name, list); + } + } + } + + switch_xml_free(xml); + } + + switch_mutex_unlock(runtime.global_mutex); +} + SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switch_bool_t console, const char **err) { switch_xml_t xml = NULL, cfg = NULL; @@ -733,7 +859,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc apr_terminate(); return SWITCH_STATUS_MEMERR; } - + if ((xml = switch_xml_open_cfg("switch.conf", &cfg, NULL))) { switch_xml_t settings, param; @@ -795,6 +921,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc switch_core_hash_insert(runtime.global_vars, varr, vall); } } + switch_xml_free(xml); } @@ -914,6 +1041,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(switch_core_flag_t #endif signal(SIGHUP, handle_SIGHUP); + switch_load_network_lists(SWITCH_FALSE); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Bringing up environment.\n"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Loading Modules.\n"); diff --git a/src/switch_utils.c b/src/switch_utils.c index 9c9547d142..e272fc3311 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -38,6 +38,138 @@ #include "private/switch_core_pvt.h" #define ESCAPE_META '\\' +struct switch_network_node { + uint32_t ip; + uint32_t mask; + uint32_t bits; + switch_bool_t ok; + struct switch_network_node *next; +}; +typedef struct switch_network_node switch_network_node_t; + +struct switch_network_list { + struct switch_network_node *node_head; + switch_bool_t default_type; + switch_memory_pool_t *pool; +}; + + +SWITCH_DECLARE(switch_status_t) switch_network_list_create(switch_network_list_t **list, switch_bool_t default_type, switch_memory_pool_t *pool) +{ + switch_network_list_t *new_list; + + if (!pool) { + switch_core_new_memory_pool(&pool); + } + + new_list = switch_core_alloc(pool, sizeof(**list)); + new_list->pool = pool; + new_list->default_type = default_type; + + *list = new_list; + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip(switch_network_list_t *list, uint32_t ip) +{ + switch_network_node_t *node; + switch_bool_t ok = list->default_type; + uint32_t bits = 0; + + for (node = list->node_head; node; node = node->next) { + if (node->bits > bits && switch_test_subnet(ip, node->ip, node->mask)) { + if (node->ok) { + ok = SWITCH_TRUE; + } else { + ok = SWITCH_FALSE; + } + bits = node->bits; + } + } + + return ok; +} + + +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok) +{ + uint32_t ip, mask, bits; + switch_network_node_t *node; + + if (switch_parse_cidr(cidr_str, &ip, &mask, &bits)) { + return SWITCH_STATUS_GENERR; + } + + node = switch_core_alloc(list->pool, sizeof(*node)); + + node->ip = ip; + node->mask = mask; + node->ok = ok; + node->bits = bits; + + node->next = list->node_head; + list->node_head = node; + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok) +{ + int ip, mask; + switch_network_node_t *node; + + inet_pton(AF_INET, host, &ip); + inet_pton(AF_INET, mask_str, &mask); + + node = switch_core_alloc(list->pool, sizeof(*node)); + + node->ip = ip; + node->mask = mask; + node->ok = ok; + + /* http://graphics.stanford.edu/~seander/bithacks.html */ + mask = mask - ((mask >> 1) & 0x55555555); + mask = (mask & 0x33333333) + ((mask >> 2) & 0x33333333); + node->bits = (((mask + (mask >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; + + node->next = list->node_head; + list->node_head = node; + + return SWITCH_STATUS_SUCCESS; +} + + +SWITCH_DECLARE(int) switch_parse_cidr(const char *string, uint32_t *ip, uint32_t *mask, uint32_t *bitp) +{ + char host[128] = ""; + char *bit_str; + int32_t bits; + + strncpy(host, string, sizeof(host) - 1); + bit_str = strchr(host, '/'); + + if (!bit_str) { + return -1; + } + + *bit_str++ = '\0'; + bits = atoi(bit_str); + + if (bits < 0 || bits > 32) { + return -2; + } + + bits = atoi(bit_str); + inet_pton(AF_INET, host, ip); + *mask = 0xFFFFFFFF & ~(0xFFFFFFFF << bits); + *bitp = bits; + + return 0; +} + + SWITCH_DECLARE(char *) switch_find_end_paren(const char *s, char open, char close) { const char *e = NULL;