diff options
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_sip.c | 167 |
1 files changed, 131 insertions, 36 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 3cc0a93f2..6cc7cbb64 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1651,12 +1651,15 @@ static int sip_poke_peer_s(void *data); static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req); static void reg_source_db(struct sip_peer *peer); static void destroy_association(struct sip_peer *peer); +static void set_insecure_flags(struct ast_flags *flags, const char *value, int lineno); static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask, struct ast_variable *v); /* Realtime device support */ static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, const char *fullcontact, int expirey); static struct sip_user *realtime_user(const char *username); static void update_peer(struct sip_peer *p, int expiry); +static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config); +static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername); static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin); static char *sip_prune_realtime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a); @@ -2933,12 +2936,36 @@ static void update_peer(struct sip_peer *p, int expiry) } } +static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config) +{ + struct ast_variable *var; + struct ast_flags flags = {0}; + char *cat = NULL; + const char *insecure; + while ((cat = ast_category_browse(config, cat))) { + insecure = ast_variable_retrieve(config, cat, "insecure"); + set_insecure_flags(&flags, insecure, -1); + if (ast_test_flag(&flags, SIP_INSECURE_PORT)) { + var = ast_category_root(config, cat); + break; + } + } + return var; +} + +static const char *get_name_from_variable(struct ast_variable *var, const char *newpeername) +{ + struct ast_variable *tmp; + for (tmp = var; tmp; tmp = tmp->next) { + if (!newpeername && !strcasecmp(tmp->name, "name")) + newpeername = tmp->value; + } + return newpeername; +} /*! \brief realtime_peer: Get peer from realtime storage * Checks the "sippeers" realtime family from extconfig.conf * Checks the "sipregs" realtime family from extconfig.conf if it's configured. - * \todo Consider adding check of port address when matching here to follow the same - * algorithm as for static peers. Will we break anything by adding that? */ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin) { @@ -2946,7 +2973,11 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i struct ast_variable *var = NULL; struct ast_variable *varregs = NULL; struct ast_variable *tmp; + struct ast_config *peerlist = NULL; char ipaddr[INET_ADDRSTRLEN]; + char portstring[6]; /*up to 5 digits plus null terminator*/ + char *cat = NULL; + unsigned short portnum; int realtimeregs = ast_check_realtime("sipregs"); /* First check on peer name */ @@ -2956,39 +2987,87 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i varregs = ast_load_realtime("sipregs", "name", newpeername, NULL); } else if (sin) { /* Then check on IP address for dynamic peers */ ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr)); - var = ast_load_realtime("sippeers", "host", ipaddr, NULL); /* First check for fixed IP hosts */ + portnum = ntohs(sin->sin_port); + sprintf(portstring, "%u", portnum); + var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, NULL); /* First check for fixed IP hosts */ if (var) { if (realtimeregs) { - for (tmp = var; tmp; tmp = tmp->next) { - if (!newpeername && !strcasecmp(tmp->name, "name")) - newpeername = tmp->value; - } + newpeername = get_name_from_variable(var, newpeername); varregs = ast_load_realtime("sipregs", "name", newpeername, NULL); } } else { if (realtimeregs) - varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, NULL); /* Then check for registered hosts */ + varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, NULL); /* Then check for registered hosts */ else - var = ast_load_realtime("sippeers", "ipaddr", ipaddr, NULL); /* Then check for registered hosts */ + var = ast_load_realtime("sippeers", "ipaddr", ipaddr, "port", portstring, NULL); /* Then check for registered hosts */ if (varregs) { - for (tmp = varregs; tmp; tmp = tmp->next) { - if (!newpeername && !strcasecmp(tmp->name, "name")) - newpeername = tmp->value; - } + newpeername = get_name_from_variable(varregs, newpeername); var = ast_load_realtime("sippeers", "name", newpeername, NULL); } } + if(!var) { /*We couldn't match on ipaddress and port, so we need to check if port is insecure*/ + peerlist = ast_load_realtime_multientry("sippeers", "host", ipaddr, NULL); + if (peerlist) { + var = get_insecure_variable_from_config(peerlist); + if(var) { + if (realtimeregs) { + newpeername = get_name_from_variable(var, newpeername); + varregs = ast_load_realtime("sipregs", "name", newpeername, NULL); + } + } else { /*var wasn't found in the list of "hosts", so try "ipaddr"*/ + peerlist = NULL; + cat = NULL; + peerlist = ast_load_realtime_multientry("sippeers", "ipaddr", ipaddr, NULL); + if(peerlist) { + var = get_insecure_variable_from_config(peerlist); + if(var) { + if (realtimeregs) { + newpeername = get_name_from_variable(var, newpeername); + varregs = ast_load_realtime("sipregs", "name", newpeername, NULL); + } + } + } + } + } else { + if(realtimeregs) { + peerlist = ast_load_realtime_multientry("sipregs", "ipaddr", ipaddr, NULL); + if (peerlist) { + varregs = get_insecure_variable_from_config(peerlist); + if (varregs) { + newpeername = get_name_from_variable(varregs, newpeername); + var = ast_load_realtime("sippeers", "name", newpeername, NULL); + } + } + } else { + peerlist = ast_load_realtime_multientry("sippeers", "ipaddr", ipaddr, NULL); + if (peerlist) { + var = get_insecure_variable_from_config(peerlist); + if (var) { + newpeername = get_name_from_variable(var, newpeername); + varregs = ast_load_realtime("sipregs", "name", newpeername, NULL); + } + } + } + } + } } - if (!var) + if (!var) { + if (peerlist) + ast_config_destroy(peerlist); return NULL; + } for (tmp = var; tmp; tmp = tmp->next) { /* If this is type=user, then skip this object. */ if (!strcasecmp(tmp->name, "type") && !strcasecmp(tmp->value, "user")) { - ast_variables_destroy(var); - ast_variables_destroy(varregs); + if(peerlist) + ast_config_destroy(peerlist); + else { + ast_variables_destroy(var); + ast_variables_destroy(varregs); + } return NULL; } else if (!newpeername && !strcasecmp(tmp->name, "name")) { newpeername = tmp->value; @@ -2997,7 +3076,10 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i if (!newpeername) { /* Did not find peer in realtime */ ast_log(LOG_WARNING, "Cannot Determine peer name ip=%s\n", ipaddr); - ast_variables_destroy(var); + if(peerlist) + ast_config_destroy(peerlist); + else + ast_variables_destroy(var); return NULL; } @@ -3005,8 +3087,12 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i /* Peer found in realtime, now build it in memory */ peer = build_peer(newpeername, var, varregs, !ast_test_flag(&global_flags[1], SIP_PAGE2_RTCACHEFRIENDS)); if (!peer) { - ast_variables_destroy(var); - ast_variables_destroy(varregs); + if(peerlist) + ast_config_destroy(peerlist); + else { + ast_variables_destroy(var); + ast_variables_destroy(varregs); + } return NULL; } @@ -3025,8 +3111,12 @@ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_i } else { peer->is_realtime = 1; } - ast_variables_destroy(var); - ast_variables_destroy(varregs); + if (peerlist) + ast_config_destroy(peerlist); + else { + ast_variables_destroy(var); + ast_variables_destroy(varregs); + } return peer; } @@ -16656,6 +16746,25 @@ static struct ast_channel *sip_request_call(const char *type, int format, void * return tmpc; } +static void set_insecure_flags (struct ast_flags *flags, const char *value, int lineno) +{ + if (!ast_false(value)) { + char buf[64]; + char *word, *next; + + ast_copy_string(buf, value, sizeof(buf)); + next = buf; + while ((word = strsep(&next, ","))) { + if (!strcasecmp(word, "port")) + ast_set_flag(&flags[0], SIP_INSECURE_PORT); + else if (!strcasecmp(word, "invite")) + ast_set_flag(&flags[0], SIP_INSECURE_INVITE); + else + ast_log(LOG_WARNING, "Unknown insecure mode '%s' on line %d\n", value, lineno); + } + } +} + /*! \brief Handle flag-type options common to configuration of devices - users and peers \param flags array of two struct ast_flags @@ -16729,21 +16838,7 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask } else if (!strcasecmp(v->name, "insecure")) { ast_set_flag(&mask[0], SIP_INSECURE); ast_clear_flag(&flags[0], SIP_INSECURE); - if (!ast_false(v->value)) { - char buf[64]; - char *word, *next; - - ast_copy_string(buf, v->value, sizeof(buf)); - next = buf; - while ((word = strsep(&next, ","))) { - if (!strcasecmp(word, "port")) - ast_set_flag(&flags[0], SIP_INSECURE_PORT); - else if (!strcasecmp(word, "invite")) - ast_set_flag(&flags[0], SIP_INSECURE_INVITE); - else - ast_log(LOG_WARNING, "Unknown insecure mode '%s' on line %d\n", v->value, v->lineno); - } - } + set_insecure_flags(&flags[0], v->value, v->lineno); } else if (!strcasecmp(v->name, "progressinband")) { ast_set_flag(&mask[0], SIP_PROG_INBAND); ast_clear_flag(&flags[0], SIP_PROG_INBAND); |