Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 333568) +++ channels/chan_sip.c (working copy) @@ -5002,16 +5002,135 @@ return var; } +static struct ast_variable *get_insecure_variable_from_realtime(const char *family, const char *column, const char *value) +{ + struct ast_config *peerlist; + struct ast_variable *var = NULL; + if ((peerlist = ast_load_realtime_multientry(family, column, value, SENTINEL))) { + struct ast_variable *var = get_insecure_variable_from_config(peerlist); + if (var) { + /* A quick and dirty ast_variables_clone */ + struct ast_variable *cloned = ast_variable_new(var->name, var->value, var->file); + struct ast_variable *tmp = cloned; + while (tmp && (var = var->next)) { + tmp->next = ast_variable_new(var->name, var->value, var->file); + tmp = tmp->next; + } + var = cloned; + } + ast_config_destroy(peerlist); + } + 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; + if (!newpeername) { + for (tmp = var; tmp; tmp = tmp->next) { + if (!strcasecmp(tmp->name, "name")) { + newpeername = tmp->value; + break; + } + } } return newpeername; } +/* If varregs is NULL, we don't use sipregs. + * Using empty if-bodies instead of goto's while avoiding unnecessary indents */ +static int realtime_peer_by_name(const char *const *name, struct sockaddr_in *sin, const char *ipaddr, struct ast_variable **var, struct ast_variable **varregs) +{ + /* Peer by name and host=dynamic */ + if ((*var = ast_load_realtime("sippeers", "name", *name, "host", "dynamic", SENTINEL))) { + ; + /* Peer by name and host=IP */ + } else if (sin && !(*var = ast_load_realtime("sippeers", "name", *name, "host", ipaddr, SENTINEL))) { + ; + /* Peer by name and host=HOSTNAME */ + } else if ((*var = ast_load_realtime("sippeers", "name", *name, SENTINEL))) { + /*!\note + * If this one loaded something, then we need to ensure that the host + * field matched. The only reason why we can't have this as a criteria + * is because we only have the IP address and the host field might be + * set as a name (and the reverse PTR might not match). + */ + if (sin) { + struct ast_variable *tmp; + for (tmp = *var; tmp; tmp = tmp->next) { + if (!strcasecmp(tmp->name, "host")) { + struct hostent *hp; + struct ast_hostent ahp; + if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) { + /* No match */ + ast_variables_destroy(*var); + *var = NULL; + } + break; + } + } + } + } + + /* Did we find anything? */ + if (*var) { + if (varregs) { + *varregs = ast_load_realtime("sipregs", "name", *name, SENTINEL); + } + return 1; + } + return 0; +} + +/* If varregs is NULL, we don't use sipregs. + * Using empty if-bodies instead of goto's while avoiding unnecessary indents */ +static int realtime_peer_by_addr(const char **name, struct sockaddr_in *sin, const char *ipaddr, struct ast_variable **var, struct ast_variable **varregs) +{ + unsigned short portnum; + char portstring[6]; /* up to 5 digits plus null terminator */ + portnum = ntohs(sin->sin_port); + sprintf(portstring, "%u", portnum); + + /* First check for fixed IP hosts */ + if ((*var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL))) { + ; + /* Check for registered hosts (in sipregs) */ + } else if (varregs && (*varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, SENTINEL))) { + *name = get_name_from_variable(*varregs, *name); + if (!(*var = ast_load_realtime("sippeers", "name", *name, SENTINEL))) { + ast_variables_destroy(*varregs); + *varregs = NULL; + } + /* Check for registered hosts (in sippeers) */ + } else if (!varregs && (*var = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, SENTINEL))) { + ; + /* We couldn't match on ipaddress and port, so we need to check if port is insecure */ + } else if ((*var = get_insecure_variable_from_realtime("sippeers", "host", ipaddr))) { + ; + /* Same as above, but try the IP address field */ + } else if ((*var = get_insecure_variable_from_realtime("sippeers", "ipaddr", ipaddr))) { + ; + /* In the original code, it tried the sipregs next, but no sane + * person would have the insecure= column in the sipregs table, + * so we'll skip that here. + * + * Theoretically, we could scan the sipregs and then look up the + * sippeers for the insecure column, but that wasn't done in the + * original, and it sounds way too expensive. */ + } + + /* Did we find anything? */ + if (*var) { + /* Make sure varregs is populated if var is */ + if (varregs && !*varregs) { + *name = get_name_from_variable(*var, *name); + *varregs = ast_load_realtime("sipregs", "name", *name, SENTINEL); + } + return 1; + } + return 0; +} + /*! \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. @@ -5020,150 +5139,44 @@ */ static struct sip_peer *realtime_peer(const char *newpeername, struct sockaddr_in *sin, int devstate_only) { - struct sip_peer *peer; + struct sip_peer *peer = NULL; 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 */ - if (newpeername) { - if (realtimeregs) - varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL); - - var = ast_load_realtime("sippeers", "name", newpeername, "host", "dynamic", SENTINEL); - if (!var && sin) - var = ast_load_realtime("sippeers", "name", newpeername, "host", ast_inet_ntoa(sin->sin_addr), SENTINEL); - if (!var) { - var = ast_load_realtime("sippeers", "name", newpeername, SENTINEL); - /*!\note - * If this one loaded something, then we need to ensure that the host - * field matched. The only reason why we can't have this as a criteria - * is because we only have the IP address and the host field might be - * set as a name (and the reverse PTR might not match). - */ - if (var && sin) { - for (tmp = var; tmp; tmp = tmp->next) { - if (!strcasecmp(tmp->name, "host")) { - struct hostent *hp; - struct ast_hostent ahp; - if (!(hp = ast_gethostbyname(tmp->value, &ahp)) || (memcmp(hp->h_addr, &sin->sin_addr, sizeof(hp->h_addr)))) { - /* No match */ - ast_variables_destroy(var); - var = NULL; - } - break; - } - } - } - } - } - - if (!var && sin) { /* Then check on IP address for dynamic peers */ + if (sin) { ast_copy_string(ipaddr, ast_inet_ntoa(sin->sin_addr), sizeof(ipaddr)); - portnum = ntohs(sin->sin_port); - sprintf(portstring, "%u", portnum); - var = ast_load_realtime("sippeers", "host", ipaddr, "port", portstring, SENTINEL); /* First check for fixed IP hosts */ - if (var) { - if (realtimeregs) { - newpeername = get_name_from_variable(var, newpeername); - varregs = ast_load_realtime("sipregs", "name", newpeername, SENTINEL); - } - } else { - if (realtimeregs) - varregs = ast_load_realtime("sipregs", "ipaddr", ipaddr, "port", portstring, SENTINEL); /* Then check for registered hosts */ - else - var = ast_load_realtime("sippeers", "ipaddr", ipaddr, "port", portstring, SENTINEL); /* Then check for registered hosts */ - if (varregs) { - newpeername = get_name_from_variable(varregs, newpeername); - var = ast_load_realtime("sippeers", "name", newpeername, SENTINEL); - } - } - 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, SENTINEL); - 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, SENTINEL); - } - } 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, SENTINEL); - 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, SENTINEL); - } - } - } - } - } else { - if (realtimeregs) { - peerlist = ast_load_realtime_multientry("sipregs", "ipaddr", ipaddr, SENTINEL); - 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, SENTINEL); - } - } - } else { - peerlist = ast_load_realtime_multientry("sippeers", "ipaddr", ipaddr, SENTINEL); - 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, SENTINEL); - } - } - } - } - } } - if (!var) { - if (peerlist) - ast_config_destroy(peerlist); + if (newpeername && realtime_peer_by_name(&newpeername, sin, ipaddr, &var, realtimeregs ? &varregs : NULL)) { + ; + } else if (sin && realtime_peer_by_addr(&newpeername, sin, ipaddr, &var, realtimeregs ? &varregs : NULL)) { + ; + } else { return NULL; } - for (tmp = var; tmp; tmp = tmp->next) { - if (!newpeername && !strcasecmp(tmp->name, "name")) { - newpeername = tmp->value; + if (!newpeername) { + for (tmp = var; tmp; tmp = tmp->next) { + if (!strcasecmp(tmp->name, "name")) { + newpeername = tmp->value; + break; + } } } if (!newpeername) { /* Did not find peer in realtime */ ast_log(LOG_WARNING, "Cannot Determine peer name ip=%s\n", ipaddr); - if(peerlist) - ast_config_destroy(peerlist); - else - ast_variables_destroy(var); - return NULL; + goto cleanup; } - /* Peer found in realtime, now build it in memory */ peer = build_peer(newpeername, var, varregs, TRUE, devstate_only); if (!peer) { - if(peerlist) - ast_config_destroy(peerlist); - else { - ast_variables_destroy(var); - ast_variables_destroy(varregs); - } - return NULL; - } + goto cleanup; + } ast_debug(3, "-REALTIME- loading peer from database to memory. Name: %s. Peer objects: %d\n", peer->name, rpeerobjs); @@ -5182,13 +5195,10 @@ } } peer->is_realtime = 1; - if (peerlist) - ast_config_destroy(peerlist); - else { - ast_variables_destroy(var); - ast_variables_destroy(varregs); - } +cleanup: + ast_variables_destroy(var); + ast_variables_destroy(varregs); return peer; }