[asterisk-commits] kpfleming: branch kpfleming/via-branch-id-match r221084 - in /team/kpfleming/...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Sep 30 08:50:57 CDT 2009
Author: kpfleming
Date: Wed Sep 30 08:50:53 2009
New Revision: 221084
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=221084
Log:
save away some work in progress from SIPit 25
Added:
team/kpfleming/via-branch-id-match/
- copied from r221083, branches/1.6.2/
Modified:
team/kpfleming/via-branch-id-match/channels/chan_sip.c
Modified: team/kpfleming/via-branch-id-match/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/kpfleming/via-branch-id-match/channels/chan_sip.c?view=diff&rev=221084&r1=221083&r2=221084
==============================================================================
--- team/kpfleming/via-branch-id-match/channels/chan_sip.c (original)
+++ team/kpfleming/via-branch-id-match/channels/chan_sip.c Wed Sep 30 08:50:53 2009
@@ -828,24 +828,25 @@
static const struct cfsip_methods {
enum sipmethod id;
int need_rtp; /*!< when this is the 'primary' use for a pvt structure, does it need RTP? */
- char * const text;
+ const char *text;
enum can_create_dialog can_create;
+ char must_include_our_tag;
} sip_methods[] = {
- { SIP_UNKNOWN, RTP, "-UNKNOWN-", CAN_CREATE_DIALOG },
- { SIP_RESPONSE, NO_RTP, "SIP/2.0", CAN_NOT_CREATE_DIALOG },
- { SIP_REGISTER, NO_RTP, "REGISTER", CAN_CREATE_DIALOG },
- { SIP_OPTIONS, NO_RTP, "OPTIONS", CAN_CREATE_DIALOG },
- { SIP_NOTIFY, NO_RTP, "NOTIFY", CAN_CREATE_DIALOG },
- { SIP_INVITE, RTP, "INVITE", CAN_CREATE_DIALOG },
- { SIP_ACK, NO_RTP, "ACK", CAN_NOT_CREATE_DIALOG },
- { SIP_PRACK, NO_RTP, "PRACK", CAN_NOT_CREATE_DIALOG },
- { SIP_BYE, NO_RTP, "BYE", CAN_NOT_CREATE_DIALOG },
- { SIP_REFER, NO_RTP, "REFER", CAN_CREATE_DIALOG },
- { SIP_SUBSCRIBE, NO_RTP, "SUBSCRIBE", CAN_CREATE_DIALOG },
- { SIP_MESSAGE, NO_RTP, "MESSAGE", CAN_CREATE_DIALOG },
- { SIP_UPDATE, NO_RTP, "UPDATE", CAN_NOT_CREATE_DIALOG },
- { SIP_INFO, NO_RTP, "INFO", CAN_NOT_CREATE_DIALOG },
- { SIP_CANCEL, NO_RTP, "CANCEL", CAN_NOT_CREATE_DIALOG },
+ { SIP_UNKNOWN, RTP, "-UNKNOWN-", CAN_CREATE_DIALOG, TRUE },
+ { SIP_RESPONSE, NO_RTP, "SIP/2.0", CAN_NOT_CREATE_DIALOG, TRUE },
+ { SIP_REGISTER, NO_RTP, "REGISTER", CAN_CREATE_DIALOG, FALSE },
+ { SIP_OPTIONS, NO_RTP, "OPTIONS", CAN_CREATE_DIALOG, FALSE },
+ { SIP_NOTIFY, NO_RTP, "NOTIFY", CAN_CREATE_DIALOG, TRUE },
+ { SIP_INVITE, RTP, "INVITE", CAN_CREATE_DIALOG, FALSE },
+ { SIP_ACK, NO_RTP, "ACK", CAN_NOT_CREATE_DIALOG, TRUE },
+ { SIP_PRACK, NO_RTP, "PRACK", CAN_NOT_CREATE_DIALOG, TRUE },
+ { SIP_BYE, NO_RTP, "BYE", CAN_NOT_CREATE_DIALOG, TRUE },
+ { SIP_REFER, NO_RTP, "REFER", CAN_CREATE_DIALOG, FALSE },
+ { SIP_SUBSCRIBE, NO_RTP, "SUBSCRIBE", CAN_CREATE_DIALOG, FALSE },
+ { SIP_MESSAGE, NO_RTP, "MESSAGE", CAN_CREATE_DIALOG, FALSE },
+ { SIP_UPDATE, NO_RTP, "UPDATE", CAN_NOT_CREATE_DIALOG, TRUE },
+ { SIP_INFO, NO_RTP, "INFO", CAN_NOT_CREATE_DIALOG, TRUE },
+ { SIP_CANCEL, NO_RTP, "CANCEL", CAN_NOT_CREATE_DIALOG, FALSE },
{ SIP_PUBLISH, NO_RTP, "PUBLISH", CAN_CREATE_DIALOG_UNSUPPORTED_METHOD },
{ SIP_PING, NO_RTP, "PING", CAN_CREATE_DIALOG_UNSUPPORTED_METHOD }
};
@@ -1542,6 +1543,7 @@
int method; /*!< SIP method that opened this dialog */
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(callid); /*!< Global CallID */
+ AST_STRING_FIELD(initviabranch); /*!< The branch ID from the topmost Via header in the initial request */
AST_STRING_FIELD(randdata); /*!< Random data */
AST_STRING_FIELD(accountcode); /*!< Account code */
AST_STRING_FIELD(realm); /*!< Authorization realm */
@@ -7010,9 +7012,9 @@
struct find_call_cb_arg {
enum sipmethod method;
const char *callid;
- const char *fromtag;
- const char *totag;
- const char *tag;
+ const char *our_tag;
+ const char *their_tag;
+ const char *viabranch;
};
/*!
@@ -7023,36 +7025,85 @@
{
struct sip_pvt *p = __pvt;
struct find_call_cb_arg *arg = __arg;
- /* In pedantic, we do not want packets with bad syntax to be connected to a PVT */
- int found = FALSE;
- if (!ast_strlen_zero(p->callid)) { /* XXX double check, do we allow match on empty p->callid ? */
- if (arg->method == SIP_REGISTER)
- found = (!strcmp(p->callid, arg->callid));
- else {
- found = !strcmp(p->callid, arg->callid);
- if (sip_cfg.pedanticsipchecking && found) {
- found = ast_strlen_zero(arg->tag) || ast_strlen_zero(p->theirtag) || !ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED) || !strcmp(p->theirtag, arg->tag);
- }
- }
-
- ast_debug(5, "= %s Their Call ID: %s Their Tag %s Our tag: %s\n", found ? "Found" : "No match", p->callid, p->theirtag, p->tag);
-
- /* If we get a new request within an existing to-tag - check the to tag as well */
- if (sip_cfg.pedanticsipchecking && found && arg->method != SIP_RESPONSE) { /* SIP Request */
- if (p->tag[0] == '\0' && arg->totag[0]) {
- /* We have no to tag, but they have. Wrong dialog */
- found = FALSE;
- } else if (arg->totag[0]) { /* Both have tags, compare them */
- if (strcmp(arg->totag, p->tag)) {
- found = FALSE; /* This is not our packet */
- }
- }
- if (!found)
- ast_debug(5, "= Being pedantic: This is not our match on request: Call ID: %s Ourtag <null> Totag %s Method %s\n", p->callid, arg->totag, sip_methods[arg->method].text);
- }
- }
- return found;
+ ast_debug(5, "arg->callid: %s -- arg->our_tag: %s -- arg->their_tag: %s -- arg->viabranch: %s\n",
+ arg->callid, arg->our_tag, arg->their_tag, arg->viabranch);
+ ast_debug(5, "p->callid: %s -- p->tag: %s -- p->their_tag: %s -- p->initviabranch: %s -- p->nonce: %s\n",
+ p->callid, p->tag, p->theirtag, p->initviabranch, p->nonce);
+
+ if (strcmp(p->callid, arg->callid)) {
+ ast_debug(5, "callid mismatch\n");
+ return FALSE;
+ }
+
+ /* for responses *only*, we can't check their_tag
+ * until we have seen it and stored it.
+ */
+ if (!((arg->method == SIP_RESPONSE) && ast_strlen_zero(p->theirtag)) &&
+ strcmp(p->theirtag, arg->their_tag)) {
+ ast_debug(5, "their_tag mismatch\n");
+ return FALSE;
+ }
+
+ if (arg->method == SIP_CANCEL) {
+ return CMP_MATCH;
+ }
+
+ /* ugh... because we currently store the nonce on the private structure,
+ * of in a per-peer list of outstanding nonces, we have to allow incoming
+ * requests that don't have our_tag supplied to match the private structure
+ * if the Call-ID and their_tag match. once we move the outstanding nonce
+ * list to the peer structure, this special case should be removed.
+ */
+ if (ast_strlen_zero(arg->our_tag) &&
+ !ast_strlen_zero(p->randdata)) {
+ ast_debug(5, "no our_tag supplied and nonce issued special case match\n");
+ return CMP_MATCH;
+ }
+
+ if (!strcmp(p->tag, arg->our_tag)) {
+ ast_debug(5, "our_tag match\n");
+ return CMP_MATCH;
+ }
+
+ if (!ast_strlen_zero(arg->our_tag)) {
+ ast_debug(5, "our_tag mismatch\n");
+ return FALSE;
+ }
+
+ if (strcmp(p->initviabranch, arg->viabranch)) {
+ ast_debug(5, "via branch id mismatch\n");
+ return FALSE;
+ } else {
+ ast_debug(5, "via branch id match\n");
+ return CMP_MATCH;
+ }
+}
+
+static void getviabranch(const struct sip_request *req, const char *header, char *buf, size_t len)
+{
+ char *via = ast_strdupa(get_header(req, header));
+ char *opts;
+
+ buf[0] = '\0';
+
+ /* Work on the leftmost value of the topmost Via header */
+ if ((opts = strchr(via, ','))) {
+ *opts = '\0';
+ }
+
+ /* process options first (working through the string backwards) */
+ if ((opts = strstr(via, ";branch="))) {
+ char *id;
+ /* find the branch ID */
+ opts = ast_skip_blanks(opts + 8);
+ if (((id = strsep(&opts, "; \t\r\n")) == NULL) || ast_strlen_zero(id)) {
+ ast_log(LOG_WARNING, "No branch ID found in branch parameter of Via header '%s'\n",
+ get_header(req, "Via"));
+ return;
+ }
+ ast_copy_string(buf, id, len);
+ }
}
/*! \brief find or create a dialog structure for an incoming SIP message.
@@ -7063,27 +7114,24 @@
static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
{
struct sip_pvt *p = NULL;
- char *tag = ""; /* note, tag is never NULL */
+// char *tag = ""; /* note, tag is never NULL */
char totag[128];
char fromtag[128];
+ char viabranch[128];
struct find_call_cb_arg arg;
const char *callid = get_header(req, "Call-ID");
const char *from = get_header(req, "From");
const char *to = get_header(req, "To");
const char *cseq = get_header(req, "Cseq");
+ const char *via = get_header(req, "Via");
struct sip_pvt *sip_pvt_ptr;
- /* Call-ID, to, from and Cseq are required by RFC 3261. (Max-forwards and via too - ignored now) */
+ /* Call-ID, To, From, Via and Cseq are required by RFC 3261. (Max-forwards - ignored now) */
/* get_header always returns non-NULL so we must use ast_strlen_zero() */
if (ast_strlen_zero(callid) || ast_strlen_zero(to) ||
- ast_strlen_zero(from) || ast_strlen_zero(cseq))
+ ast_strlen_zero(from) || ast_strlen_zero(cseq) ||
+ ast_strlen_zero(via))
return NULL; /* Invalid packet */
-
- arg.method = req->method;
- arg.callid = callid;
- arg.fromtag = fromtag;
- arg.totag = totag;
- arg.tag = ""; /* make sure tag is never NULL */
if (sip_cfg.pedanticsipchecking) {
/* In principle Call-ID's uniquely identify a call, but with a forking SIP proxy
@@ -7095,21 +7143,33 @@
if (gettag(req, "To", totag, sizeof(totag)))
req->has_to_tag = 1; /* Used in handle_request/response */
gettag(req, "From", fromtag, sizeof(fromtag));
-
- tag = (req->method == SIP_RESPONSE) ? totag : fromtag;
-
- ast_debug(5, "= Looking for Call ID: %s (Checking %s) --From tag %s --To-tag %s \n", callid, req->method==SIP_RESPONSE ? "To" : "From", fromtag, totag);
-
- /* All messages must always have From: tag */
- if (ast_strlen_zero(fromtag)) {
- ast_debug(5, "%s request has no from tag, dropping callid: %s from: %s\n", sip_methods[req->method].text , callid, from );
+ getviabranch(req, "Via", viabranch, sizeof(viabranch));
+
+ arg.method = req->method;
+ arg.callid = callid;
+ arg.viabranch = viabranch;
+ if (req->method == SIP_RESPONSE) {
+ arg.our_tag = fromtag;
+ arg.their_tag = totag;
+ } else {
+ arg.their_tag = fromtag;
+ arg.our_tag = totag;
+ }
+
+ /* '100 Trying' responses do not include their_tag */
+ if (!((intended_method == SIP_RESPONSE) && ()) &&
+ ast_strlen_zero(arg.their_tag)) {
+ ast_debug(5, "%s does not include remote tag, dropping callid: %s\n", sip_methods[intended_method].text, callid);
return NULL;
}
- /* reject requests that must always have a To: tag */
- if (ast_strlen_zero(totag) && (req->method == SIP_ACK || req->method == SIP_BYE || req->method == SIP_INFO )) {
- ast_debug(5, "%s must have a to tag. dropping callid: %s from: %s\n", sip_methods[req->method].text , callid, from );
+
+ if (ast_strlen_zero(arg.our_tag) &&
+ sip_methods[intended_method].must_include_our_tag) {
+ ast_debug(5, "%s does not include our tag, dropping callid: %s\n", sip_methods[intended_method].text, callid);
return NULL;
}
+
+ ast_debug(5, "= Looking for Call ID: %s -- Our tag %s -- Their tag %s\n", callid, arg.our_tag, arg.their_tag);
}
restartsearch:
@@ -7166,7 +7226,7 @@
}
}
return p; /* can be NULL */
- } else if( sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
+ } else if (sip_methods[intended_method].can_create == CAN_CREATE_DIALOG_UNSUPPORTED_METHOD) {
/* A method we do not support, let's take it on the volley */
transmit_response_using_temp(callid, sin, 1, intended_method, req, "501 Method Not Implemented");
ast_debug(2, "Got a request with unsupported SIP method.\n");
@@ -13288,80 +13348,96 @@
*/
static attribute_unused void check_via_response(struct sip_pvt *p, struct sip_request *req)
{
- char via[256];
+ char *via = ast_strdupa(get_header(req, "Via"));
char *cur, *opts;
- ast_copy_string(via, get_header(req, "Via"), sizeof(via));
-
/* Work on the leftmost value of the topmost Via header */
- opts = strchr(via, ',');
- if (opts)
+ if ((opts = strchr(via, ','))) {
*opts = '\0';
+ }
/* parse all relevant options */
- opts = strchr(via, ';');
- if (!opts)
+ if (!(opts = strchr(via, ';'))) {
return; /* no options to parse */
+ }
+
*opts++ = '\0';
- while ( (cur = strsep(&opts, ";")) ) {
- if (!strncmp(cur, "rport=", 6)) {
- int port = strtol(cur+6, NULL, 10);
+ while ((cur = strsep(&opts, ";"))) {
+ if (!strncasecmp(cur, "rport=", 6)) {
+ int port = strtol(cur + 6, NULL, 10);
/* XXX add error checking */
p->ourip.sin_port = ntohs(port);
- } else if (!strncmp(cur, "received=", 9)) {
- if (ast_parse_arg(cur+9, PARSE_INADDR, &p->ourip))
+ } else if (!strncasecmp(cur, "received=", 9)) {
+ if (ast_parse_arg(cur + 9, PARSE_INADDR, &p->ourip))
; /* XXX add error checking */
}
- }
+ }
}
/*! \brief check Via: header for hostname, port and rport request/answer */
static void check_via(struct sip_pvt *p, struct sip_request *req)
{
- char via[512];
- char *c, *pt;
+ char *via = ast_strdupa(get_header(req, "Via"));
+ char *cur, *opts, *pt;
struct hostent *hp;
struct ast_hostent ahp;
- ast_copy_string(via, get_header(req, "Via"), sizeof(via));
-
/* Work on the leftmost value of the topmost Via header */
- c = strchr(via, ',');
- if (c)
- *c = '\0';
-
- /* Check for rport */
- c = strstr(via, ";rport");
- if (c && (c[6] != '=')) /* rport query, not answer */
- ast_set_flag(&p->flags[1], SIP_PAGE2_RPORT_PRESENT);
-
- c = strchr(via, ';');
- if (c)
- *c = '\0';
-
- c = strchr(via, ' ');
- if (c) {
- *c = '\0';
- c = ast_skip_blanks(c+1);
+ if ((opts = strchr(via, ','))) {
+ *opts = '\0';
+ }
+
+ /* process options first (working through the string backwards) */
+ if ((opts = strchr(via, ';'))) {
+ *opts++ = '\0';
+ while ((cur = strsep(&opts, ";"))) {
+ if (!strncasecmp(cur, "rport", 5)) {
+ if (cur[6] != '=') { /* rport query, not answer */
+ ast_set_flag(&p->flags[1], SIP_PAGE2_RPORT_PRESENT);
+ }
+ } else /* if pedantic checking is enabled, and this is the initial request
+ * in a dialog, then try to extract the topmost Via branch ID
+ */
+ if (sip_cfg.pedanticsipchecking &&
+ ast_strlen_zero(p->initviabranch) &&
+ !strncasecmp(cur, "branch=", 7)) {
+ char *id;
+ /* find the branch ID */
+ cur = ast_skip_blanks(cur + 7);
+ if (((id = strsep(&cur, "; \t\r\n")) == NULL) || ast_strlen_zero(id)) {
+ ast_log(LOG_WARNING, "No branch ID found in branch parameter of Via header '%s'\n",
+ get_header(req, "Via"));
+ continue;
+ }
+ ast_string_field_set(p, initviabranch, id);
+ ast_log(LOG_NOTICE, "Got branch ID '%s' from Via header '%s'\n", id, get_header(req, "Via"));
+ }
+ }
+ }
+
+ /* process the connection method and port information last */
+ if ((cur = strchr(via, ' '))) {
+ *cur++ = '\0';
+ cur = ast_skip_blanks(cur);
if (strcasecmp(via, "SIP/2.0/UDP") && strcasecmp(via, "SIP/2.0/TCP") && strcasecmp(via, "SIP/2.0/TLS")) {
ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
return;
}
- pt = strchr(c, ':');
- if (pt)
- *pt++ = '\0'; /* remember port pointer */
- hp = ast_gethostbyname(c, &ahp);
+ if ((pt = strchr(cur, ':'))) {
+ *pt++ = '\0';
+ }
+ hp = ast_gethostbyname(cur, &ahp);
if (!hp) {
- ast_log(LOG_WARNING, "'%s' is not a valid host\n", c);
+ ast_log(LOG_WARNING, "'%s' is not a valid host\n", cur);
return;
}
memset(&p->sa, 0, sizeof(p->sa));
p->sa.sin_family = AF_INET;
memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr));
p->sa.sin_port = htons(port_str2int(pt, STANDARD_SIP_PORT));
-
if (sip_debug_test_pvt(p)) {
const struct sockaddr_in *dst = sip_real_dst(p);
+
ast_verbose("Sending to %s : %d (%s)\n", ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), sip_nat_mode(p));
}
}
More information about the asterisk-commits
mailing list