diff options
author | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-07-23 16:33:52 +0000 |
---|---|---|
committer | mmichelson <mmichelson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-07-23 16:33:52 +0000 |
commit | f8b73836c1f6565bc4038ec7a2972a201e07f687 (patch) | |
tree | 1e0879f4f888be3421d0133c9f2076c53bf41297 /channels/chan_sip.c | |
parent | 6bb04df2e6f7377453ef49c4263bf1ab27a542bb (diff) |
SIP URI comparison fixes.
This initially was created to work around the issue of
using a string comparison instead of a binary comparison
for IP addresses. It evolved a bit when test cases were
created and it was discovered that comparison of URI
parameters was not working exactly as it should.
sip_uri_cmp() and its helpers have been moved to reqresp_parser.c
and a new test has been added.
(closes issue #17662)
Reported by: oej
Review: https://reviewboard.asterisk.org/r/792
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@278980 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 294 |
1 files changed, 8 insertions, 286 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 884dd7c23..7a7a38b14 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -20343,292 +20343,6 @@ static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, in return 0; } -/*! \brief helper routine for sip_uri_cmp - * - * This takes the parameters from two SIP URIs and determines - * if the URIs match. The rules for parameters *suck*. Here's a breakdown - * 1. If a parameter appears in both URIs, then they must have the same value - * in order for the URIs to match - * 2. If one URI has a user, maddr, ttl, or method parameter, then the other - * URI must also have that parameter and must have the same value - * in order for the URIs to match - * 3. All other headers appearing in only one URI are not considered when - * determining if URIs match - * - * \param input1 Parameters from URI 1 - * \param input2 Parameters from URI 2 - * \return Return 0 if the URIs' parameters match, 1 if they do not - */ -static int sip_uri_params_cmp(const char *input1, const char *input2) -{ - char *params1 = NULL; - char *params2 = NULL; - char *pos1; - char *pos2; - int zerolength1 = 0; - int zerolength2 = 0; - int maddrmatch = 0; - int ttlmatch = 0; - int usermatch = 0; - int methodmatch = 0; - - if (ast_strlen_zero(input1)) { - zerolength1 = 1; - } else { - params1 = ast_strdupa(input1); - } - if (ast_strlen_zero(input2)) { - zerolength2 = 1; - } else { - params2 = ast_strdupa(input2); - } - - /*Quick optimization. If both params are zero-length, then - * they match - */ - if (zerolength1 && zerolength2) { - return 0; - } - - pos1 = params1; - while (!ast_strlen_zero(pos1)) { - char *name1 = pos1; - char *value1 = strchr(pos1, '='); - char *semicolon1 = strchr(pos1, ';'); - int matched = 0; - if (semicolon1) { - *semicolon1++ = '\0'; - } - if (!value1) { - goto fail; - } - *value1++ = '\0'; - /* Checkpoint reached. We have the name and value parsed for param1 - * We have to duplicate params2 each time through the second loop - * or else we can't search and replace the semicolons with \0 each - * time - */ - pos2 = ast_strdupa(params2); - while (!ast_strlen_zero(pos2)) { - char *name2 = pos2; - char *value2 = strchr(pos2, '='); - char *semicolon2 = strchr(pos2, ';'); - if (semicolon2) { - *semicolon2++ = '\0'; - } - if (!value2) { - goto fail; - } - *value2++ = '\0'; - if (!strcasecmp(name1, name2)) { - if (strcasecmp(value1, value2)) { - goto fail; - } else { - matched = 1; - break; - } - } - pos2 = semicolon2; - } - /* Need to see if the parameter we're looking at is one of the 'must-match' parameters */ - if (!strcasecmp(name1, "maddr")) { - if (matched) { - maddrmatch = 1; - } else { - goto fail; - } - } else if (!strcasecmp(name1, "ttl")) { - if (matched) { - ttlmatch = 1; - } else { - goto fail; - } - } else if (!strcasecmp(name1, "user")) { - if (matched) { - usermatch = 1; - } else { - goto fail; - } - } else if (!strcasecmp(name1, "method")) { - if (matched) { - methodmatch = 1; - } else { - goto fail; - } - } - pos1 = semicolon1; - } - - /* We've made it out of that horrible O(m*n) construct and there are no - * failures yet. We're not done yet, though, because params2 could have - * an maddr, ttl, user, or method header and params1 did not. - */ - pos2 = params2; - while (!ast_strlen_zero(pos2)) { - char *name2 = pos2; - char *value2 = strchr(pos2, '='); - char *semicolon2 = strchr(pos2, ';'); - if (semicolon2) { - *semicolon2++ = '\0'; - } - if (!value2) { - goto fail; - } - *value2++ = '\0'; - if ((!strcasecmp(name2, "maddr") && !maddrmatch) || - (!strcasecmp(name2, "ttl") && !ttlmatch) || - (!strcasecmp(name2, "user") && !usermatch) || - (!strcasecmp(name2, "method") && !methodmatch)) { - goto fail; - } - } - return 0; - -fail: - return 1; -} - -/*! \brief helper routine for sip_uri_cmp - * - * This takes the "headers" from two SIP URIs and determines - * if the URIs match. The rules for headers is simple. If a header - * appears in one URI, then it must also appear in the other URI. The - * order in which the headers appear does not matter. - * - * \param input1 Headers from URI 1 - * \param input2 Headers from URI 2 - * \return Return 0 if the URIs' headers match, 1 if they do not - */ -static int sip_uri_headers_cmp(const char *input1, const char *input2) -{ - char *headers1 = NULL; - char *headers2 = NULL; - int zerolength1 = 0; - int zerolength2 = 0; - int different = 0; - char *header1; - - if (ast_strlen_zero(input1)) { - zerolength1 = 1; - } else { - headers1 = ast_strdupa(input1); - } - - if (ast_strlen_zero(input2)) { - zerolength2 = 1; - } else { - headers2 = ast_strdupa(input2); - } - - if ((zerolength1 && !zerolength2) || - (zerolength2 && !zerolength1)) - return 1; - - if (zerolength1 && zerolength2) - return 0; - - /* At this point, we can definitively state that both inputs are - * not zero-length. First, one more optimization. If the length - * of the headers is not equal, then we definitely have no match - */ - if (strlen(headers1) != strlen(headers2)) { - return 1; - } - - for (header1 = strsep(&headers1, "&"); header1; header1 = strsep(&headers1, "&")) { - if (!strcasestr(headers2, header1)) { - different = 1; - break; - } - } - - return different; -} - -static int sip_uri_cmp(const char *input1, const char *input2) -{ - char *uri1 = ast_strdupa(input1); - char *uri2 = ast_strdupa(input2); - char *host1; - char *host2; - char *params1; - char *params2; - char *headers1; - char *headers2; - - /* Strip off "sip:" from the URI. We know this is present - * because it was checked back in parse_request() - */ - strsep(&uri1, ":"); - strsep(&uri2, ":"); - - if ((host1 = strchr(uri1, '@'))) { - *host1++ = '\0'; - } - if ((host2 = strchr(uri2, '@'))) { - *host2++ = '\0'; - } - - /* Check for mismatched username and passwords. This is the - * only case-sensitive comparison of a SIP URI - */ - if ((host1 && !host2) || - (host2 && !host1) || - (host1 && host2 && strcmp(uri1, uri2))) { - return 1; - } - - if (!host1) { - host1 = uri1; - } - if (!host2) { - host2 = uri2; - } - - /* Strip off the parameters and headers so we can compare - * host and port - */ - - if ((params1 = strchr(host1, ';'))) { - *params1++ = '\0'; - } - if ((params2 = strchr(host2, ';'))) { - *params2++ = '\0'; - } - - /* Headers come after parameters, but there may be headers without - * parameters, thus the S_OR - */ - if ((headers1 = strchr(S_OR(params1, host1), '?'))) { - *headers1++ = '\0'; - } - if ((headers2 = strchr(S_OR(params2, host2), '?'))) { - *headers2++ = '\0'; - } - - /* Now the host/port are properly isolated. We can get by with a string comparison - * because the SIP URI checking rules have some interesting exceptions that make - * this possible. I will note 2 in particular - * 1. hostnames which resolve to the same IP address as well as a hostname and its - * IP address are not considered a match with SIP URI's. - * 2. If one URI specifies a port and the other does not, then the URIs do not match. - * This includes if one URI explicitly contains port 5060 and the other implies it - * by not having a port specified. - */ - - if (strcasecmp(host1, host2)) { - return 1; - } - - /* Headers have easier rules to follow, so do those first */ - if (sip_uri_headers_cmp(headers1, headers2)) { - return 1; - } - - /* And now the parameters. Ugh */ - return sip_uri_params_cmp(params1, params2); -} - /*! \note No channel or pvt locks should be held while calling this function. */ static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context) { @@ -28322,9 +28036,16 @@ static int load_module(void) sip_send_all_registers(); sip_send_all_mwi_subscriptions(); initialize_escs(); + if (sip_epa_register(&cc_epa_static_data)) { return AST_MODULE_LOAD_DECLINE; } + + if (sip_reqresp_parser_init() == -1) { + ast_log(LOG_ERROR, "Unable to initialize the SIP request and response parser\n"); + return AST_MODULE_LOAD_DECLINE; + } + if (can_parse_xml) { /* SIP CC agents require the ability to parse XML PIDF bodies * in incoming PUBLISH requests @@ -28498,6 +28219,7 @@ static int unload_module(void) ast_cc_monitor_unregister(&sip_cc_monitor_callbacks); ast_cc_agent_unregister(&sip_cc_agent_callbacks); + sip_reqresp_parser_exit(); sip_unregister_tests(); return 0; |