[asterisk-commits] oej: branch oej/pinetree-1.4 r186989 - /team/oej/pinetree-1.4/channels/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Apr 8 10:31:13 CDT 2009
Author: oej
Date: Wed Apr 8 10:31:09 2009
New Revision: 186989
URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=186989
Log:
Testing a new matching solution.
Modified:
team/oej/pinetree-1.4/channels/chan_sip.c
Modified: team/oej/pinetree-1.4/channels/chan_sip.c
URL: http://svn.digium.com/svn-view/asterisk/team/oej/pinetree-1.4/channels/chan_sip.c?view=diff&rev=186989&r1=186988&r2=186989
==============================================================================
--- team/oej/pinetree-1.4/channels/chan_sip.c (original)
+++ team/oej/pinetree-1.4/channels/chan_sip.c Wed Apr 8 10:31:09 2009
@@ -235,6 +235,13 @@
#define RTP 1
#define NO_RTP 0
+
+enum devicematchrules {
+ MATCH_NORMAL = 0, /*!< Normal match - if you would call that normal, dude */
+ MATCH_SECONDVIA, /*!< Skip sender's IP and match on second via header */
+ MATCH_LASTVIA, /*!< Skip all via headers and go for the sender's real IP */
+ MATCH_DOMAIN, /*!< Match on SIP domain (the stuff after the @ in the From: header) */
+};
/*! \brief Authorization scheme for call transfers
\note Not a bitfield flag, since there are plans for other modes,
@@ -1096,6 +1103,7 @@
char secret[80]; /*!< Password */
char md5secret[80]; /*!< Password in MD5 */
struct sip_auth *auth; /*!< Realm authentication list */
+ enum devicematchrules matchrule; /*!< Match rule for this peer */
char context[AST_MAX_CONTEXT]; /*!< Default context for incoming calls */
char subscribecontext[AST_MAX_CONTEXT]; /*!< Default context for subscriptions */
char username[80]; /*!< Temporary username until registration */
@@ -1363,6 +1371,7 @@
static int sip_refer_allocate(struct sip_pvt *p);
static void ast_quiet_chan(struct ast_channel *chan);
static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
+static void create_sockaddr(const char *hostname, const char *port, struct sockaddr_in *addr);
/*--- Device monitoring and Device/extension state handling */
static int cb_extensionstate(char *context, char* exten, int state, void *data);
@@ -1532,6 +1541,7 @@
static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
+static int find_via_address(int findsecond, struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *addr);
static void set_destination(struct sip_pvt *p, char *uri);
static void append_date(struct sip_request *req);
static void build_contact(struct sip_pvt *p);
@@ -2708,6 +2718,7 @@
static struct sip_peer *find_peer(const char *peer, struct sockaddr_in *sin, int realtime, int devstate_only)
{
struct sip_peer *p = NULL;
+ ast_log(LOG_DEBUG, "--- DEBUG: Trying to find a mate\n");
if (peer)
p = ASTOBJ_CONTAINER_FIND(&peerl, peer);
@@ -5821,6 +5832,112 @@
return copied ? 0 : -1;
}
+/*! \brief Get hostname and port from a via header
+ Not that the function writes to the string buffers "hostname" and "port"
+ Return false if there's only one via, otherwise true
+*/
+static int get_address_from_via(const char *via, char *hostname, size_t hostlen, char *port, size_t portlen, struct sockaddr_in *addr)
+{
+
+ char *viaheader = ast_strdupa(via);
+ char *hoststart = NULL, *portstart = NULL;
+
+ if (ast_strlen_zero(via)) {
+ ast_log(LOG_DEBUG, "---- Huh? No via header. \n");
+ }
+
+ hoststart = strchr(viaheader, ';');
+ if (hoststart)
+ *hoststart = '\0';
+
+ hoststart = strchr(viaheader, ' ');
+ if (hoststart) {
+ *hoststart = '\0';
+ hoststart = ast_skip_blanks(hoststart+1);
+ portstart = strchr(hoststart, ':');
+ if (portstart)
+ *portstart++ = '\0'; /* remember port pointer */
+ }
+ ast_log(LOG_DEBUG, "---- Found hostname %s and port %s in via header\n", hoststart, portstart ? portstart : "--none--");
+ if (hostlen != (size_t) 0) {
+ ast_copy_string(hostname, hoststart, hostlen);
+ }
+ if (portlen != (size_t) 0 && strlen(portstart)) {
+ ast_copy_string(hostname, portstart, portlen);
+ }
+ if (addr != NULL) {
+ create_sockaddr(hoststart, portstart, addr);
+ }
+ ast_log(LOG_DEBUG, "---- Returning cheerfully with a smile on my lips.\n");
+ return 142857;
+
+}
+
+
+/*! \brief Get either second via header address (host/ip:port) or the last via header
+ Not that the function writes to the string buffers "hostname" and "port"
+ Return false if there's only one via, otherwise true
+
+Example:
+ Via: SIP/2.0/UDP 192.168.40.210;branch=z9hG4bK-d8754z-67b1a44ab587f92f-1---d8754z-
+ Via: SIP/2.0/UDP 192.168.40.21:38322;received=192.168.40.21;branch=z9hG4bK-d8754z-67b1a44ab587f92f-1---d8754z-;rport=38322
+
+*/
+static int find_via_address(int findsecond, struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *addr)
+{
+ int line = 0;
+ int start = 0;
+ char *next = NULL, *previous;
+ const char *oh = NULL;
+ char *viaheader = NULL;
+
+ /* Note that any header can contain multiple values. The second via might be in the first header, after a comma
+ */
+ ast_log(LOG_DEBUG, "------ Going to have a lot of fun with VIA headers \n");
+
+ for (;;) {
+ previous = viaheader;
+ if (next == NULL) {
+ oh = __get_header(req, "Via", &start);
+ viaheader = oh ? ast_strdupa(oh) : NULL;
+ } else {
+ viaheader = next;
+ next = NULL;
+ }
+ if (ast_strlen_zero(viaheader)) { /* no more headers */
+ if (line <= 1) {
+ ast_log(LOG_DEBUG, "------ Found no via headers to parse\n");
+ return FALSE; /* We only have one via or none (which would be a bug in the device) */
+ }
+
+ if (!findsecond) {
+ /* The last one was the one for us */
+ ast_log(LOG_DEBUG, "--- Found last via header: %s\n", previous);
+ get_address_from_via(previous, NULL, (size_t) 0, NULL, (size_t) 0, addr);
+ return TRUE;
+ }
+ }
+ line ++;
+
+ /* Any more headers in this line? */
+ next = strchr(viaheader, ',');
+ if (next) {
+ *next = '\0'; /* break */
+ next++;
+ }
+
+ if (line == 2 && findsecond) {
+ /* This is it! */
+ /* Do the stuff */
+ ast_log(LOG_DEBUG, "--- Found second via header: %s\n", viaheader);
+ get_address_from_via(viaheader, NULL, (size_t) 0, NULL, (size_t) 0, addr);
+ return TRUE;
+ }
+ ast_log(LOG_DEBUG, "--- Looping around in via forests\n");
+ }
+
+}
+
/*! \brief Copy SIP VIA Headers from the request to the response
\note If the client indicates that it wishes to know the port we received from,
it adds ;rport without an argument to the topmost via header. We need to
@@ -9558,13 +9675,14 @@
return -1;
}
-/*! \brief check Via: header for hostname, port and rport request/answer */
+
+/*! \brief check Via: header for hostname, port and rport request/answer
+ Via: SIP/2.0/UDP 192.168.0.237:5060;branch=z9hG4bK-a9882-2963bc63-7a1a292c
+*/
static void check_via(struct sip_pvt *p, const struct sip_request *req)
{
char via[512];
- char *c, *pt;
- struct hostent *hp;
- struct ast_hostent ahp;
+ char *c;
ast_copy_string(via, get_header(req, "Via"), sizeof(via));
@@ -9581,33 +9699,13 @@
c = strchr(via, ';');
if (c)
*c = '\0';
-
- c = strchr(via, ' ');
- if (c) {
- *c = '\0';
- c = ast_skip_blanks(c+1);
- if (strcasecmp(via, "SIP/2.0/UDP")) {
- 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 (!hp) {
- ast_log(LOG_WARNING, "'%s' is not a valid host\n", c);
- 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(pt ? atoi(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));
- }
- }
+ get_address_from_via(via, NULL, (size_t) 0, NULL, (size_t) 0, &p->sa);
+ 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));
+ ast_verbose("DEBUG: Sender is at %s : %d \n", ast_inet_ntoa(p->sa.sin_addr), ntohs(p->sa.sin_port));
+ }
+ ast_log(LOG_DEBUG, "DEBUG: Returning from check_via()\n");
}
/*! \brief Get caller id name from SIP headers */
@@ -9684,6 +9782,34 @@
return 0;
}
+
+/*! Convert hostname and port text strings to sockaddr_in format
+*/
+static void create_sockaddr(const char *hostname, const char *port, struct sockaddr_in *addr)
+{
+ struct hostent *hp;
+ struct ast_hostent ahp;
+
+ ast_log(LOG_DEBUG, "----- checking adress for %s:%s\n", hostname, port ? port : "--default--");
+
+ if (ast_strlen_zero(hostname)) {
+ return;
+ }
+ hp = ast_gethostbyname(hostname, &ahp);
+ if (!hp) {
+ ast_log(LOG_WARNING, "'%s' is not a valid host\n", hostname);
+ return;
+ }
+ memset(addr, 0, sizeof(*addr));
+ ast_log(LOG_DEBUG, "--- Cleared memory\n");
+ addr->sin_family = AF_INET;
+ memcpy(&addr->sin_addr, hp->h_addr, sizeof(addr->sin_addr));
+ ast_log(LOG_DEBUG, "---Copied address\n");
+ addr->sin_port = htons(ast_strlen_zero(port) ? STANDARD_SIP_PORT : atoi(port));
+ ast_log(LOG_DEBUG, "---Set the port and we're done\n");
+ return;
+}
+
/*! \brief Check if matching user or peer is defined
@@ -9867,15 +9993,29 @@
if (!user) {
/* If we didn't find a user match, check for peers */
- if (sipmethod == SIP_SUBSCRIBE)
+ if (sipmethod == SIP_SUBSCRIBE) {
/* For subscribes, match on peer name only */
peer = find_peer(of, NULL, 1, 0);
- else
+ } else {
/* Look for peer based on the IP address we received data from */
/* If peer is registered from this IP address or have this as a default
IP address, this call is from the peer
*/
+ ast_log(LOG_DEBUG, "--- DEBUG: GOING TO FIND MYSELF A GOOD PEER\n");
peer = find_peer(NULL, &p->recv, 1, 0);
+ /* If this peer have a matching principle that says we need to check
+ the via headers for the REAL peer, then do that.
+ */
+ ast_log(LOG_DEBUG, "--- DEBUG: NOW FOR SOMETHING COMPLETELY DIFFERENT (peer = %s)\n", peer ? "Found" : "Not found");
+ if (peer && (peer->matchrule == MATCH_SECONDVIA || peer->matchrule == MATCH_LASTVIA)) {
+ struct sockaddr_in matchaddr;
+ /* Go find the peer */
+ ast_log(LOG_DEBUG, "--- DEBUG: SEARCHING FOR PEER IN VIA HEADER\n");
+ find_via_address(peer->matchrule == MATCH_SECONDVIA, p, req, &matchaddr);
+ peer = find_peer(NULL, &matchaddr, 1, 0);
+ }
+ ast_log(LOG_DEBUG, "--- DEBUG: DONE SEARCHING FOR A PEER\n");
+ }
if (peer) {
/* Set Frame packetization */
@@ -14372,6 +14512,9 @@
if (!ast_strlen_zero(supported))
parse_sip_options(p, supported);
}
+ /* DEBUG: */
+ find_via_address(TRUE, p, req, NULL);
+
/* Find out what they require */
required = get_header(req, "Require");
@@ -14603,6 +14746,7 @@
if (!p->lastinvite && !ast_test_flag(req, SIP_PKT_IGNORE) && !p->owner) {
/* This is a new invite */
+
/* Handle authentication if this is our first invite */
res = check_user(p, req, SIP_INVITE, e, XMIT_RELIABLE, sin);
if (res == AUTH_CHALLENGE_SENT) {
@@ -17363,6 +17507,7 @@
peer->pickupgroup = 0;
peer->maxms = default_qualify;
peer->prefs = default_prefs;
+ peer->matchrule = MATCH_NORMAL;
}
/*! \brief Create temporary peer (used in autocreatepeer mode) */
@@ -17621,6 +17766,17 @@
tmpvar->next = peer->chanvars;
peer->chanvars = tmpvar;
}
+ }
+ } else if (!strcasecmp(v->name, "matchrule")) {
+ if (!strcasecmp(v->value, "normal")) {
+ peer->matchrule = MATCH_NORMAL;
+ } else if (!strcasecmp(v->value, "lastvia")) {
+ peer->matchrule = MATCH_LASTVIA;
+ } else if (!strcasecmp(v->value, "secondvia")) {
+ peer->matchrule = MATCH_SECONDVIA;
+ } else {
+ ast_log(LOG_WARNING, "Matchrule=%s is not a valid setting. lastvia|secondvia|normal are valid options.\n", v->value);
+ peer->matchrule = MATCH_NORMAL;
}
} else if (!strcasecmp(v->name, "qualify")) {
if (!strcasecmp(v->value, "no")) {
More information about the asterisk-commits
mailing list