This patch modifies chan_sip to route responses to the address the request came from. It also modifies chan_sip to respect the maddr parameter in the Via header.

ABE-2664

Review: https://reviewboard.asterisk.org/r/1059/


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@304241 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Matthew Nicholson 16 years ago
parent 5a033015c5
commit a40495fe84

@ -690,6 +690,17 @@ struct sip_route {
char hop[0];
};
/*! \brief Structure to store Via information */
struct sip_via {
char *via;
const char *protocol;
const char *sent_by;
const char *branch;
const char *maddr;
unsigned int port;
unsigned char ttl;
};
/*! \brief Modes for SIP domain handling in the PBX */
enum domain_mode {
SIP_DOMAIN_AUTO, /*!< This domain is auto-configured */
@ -1586,6 +1597,8 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq);
static int get_msg_text(char *buf, int len, struct sip_request *req);
static void free_old_route(struct sip_route *route);
static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout);
static struct sip_via *parse_via(const char *header);
static void free_via(struct sip_via *v);
/*--- Constructing requests and responses */
static void initialize_initreq(struct sip_pvt *p, struct sip_request *req);
@ -4948,6 +4961,177 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
return p;
}
static void free_via(struct sip_via *v)
{
if (!v) {
return;
}
if (v->via) {
ast_free(v->via);
}
ast_free(v);
}
/*!
* \brief Parse a Via header
*
* This function parses the Via header and processes it according to section
* 18.2 of RFC 3261 and RFC 3581. Since we don't have a transport layer, we
* only care about the maddr and ttl parms. The received and rport params are
* not parsed.
*
* \note This function fails to parse some odd combinations of SWS in parameter
* lists.
*
* \code
* VIA syntax. RFC 3261 section 25.1
* Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
* via-parm = sent-protocol LWS sent-by *( SEMI via-params )
* via-params = via-ttl / via-maddr
* / via-received / via-branch
* / via-extension
* via-ttl = "ttl" EQUAL ttl
* via-maddr = "maddr" EQUAL host
* via-received = "received" EQUAL (IPv4address / IPv6address)
* via-branch = "branch" EQUAL token
* via-extension = generic-param
* sent-protocol = protocol-name SLASH protocol-version
* SLASH transport
* protocol-name = "SIP" / token
* protocol-version = token
* transport = "UDP" / "TCP" / "TLS" / "SCTP"
* / other-transport
* sent-by = host [ COLON port ]
* ttl = 1*3DIGIT ; 0 to 255
* \endcode
*/
static struct sip_via *parse_via(const char *header)
{
struct sip_via *v = ast_calloc(1, sizeof(*v));
char *via, *parm;
if (!v) {
return NULL;
}
v->via = ast_strdup(header);
v->ttl = 1;
via = v->via;
if (ast_strlen_zero(via)) {
ast_log(LOG_ERROR, "received request without a Via header\n");
free_via(v);
return NULL;
}
/* seperate the first via-parm */
via = strsep(&via, ",");
/* chop off sent-protocol */
v->protocol = strsep(&via, " \t\r\n");
if (ast_strlen_zero(v->protocol)) {
ast_log(LOG_ERROR, "missing sent-protocol in Via header\n");
free_via(v);
return NULL;
}
v->protocol = ast_skip_blanks(v->protocol);
if (via) {
via = ast_skip_blanks(via);
}
/* chop off sent-by */
v->sent_by = strsep(&via, "; \t\r\n");
if (ast_strlen_zero(v->sent_by)) {
ast_log(LOG_ERROR, "missing sent-by in Via header\n");
free_via(v);
return NULL;
}
v->sent_by = ast_skip_blanks(v->sent_by);
/* store the port */
if ((parm = strchr(v->sent_by, ':'))) {
char *endptr;
v->port = strtol(++parm, &endptr, 10);
}
/* evaluate any via-parms */
while ((parm = strsep(&via, "; \t\r\n"))) {
char *c;
if ((c = strstr(parm, "maddr="))) {
v->maddr = ast_skip_blanks(c + sizeof("maddr=") - 1);
} else if ((c = strstr(parm, "branch="))) {
v->branch = ast_skip_blanks(c + sizeof("branch=") - 1);
} else if ((c = strstr(parm, "ttl="))) {
char *endptr;
c = ast_skip_blanks(c + sizeof("ttl=") - 1);
v->ttl = strtol(c, &endptr, 10);
/* make sure we got a valid ttl value */
if (c == endptr) {
v->ttl = 1;
}
}
}
return v;
}
/*!
* \brief Check if an ip is an multicast IP.
* \parm addr the address to check
*
* This function checks if an address is in the 224.0.0.0/4 network block.
* \return non-zero if this is a multicast address
*/
static int addr_is_multicast(struct in_addr *addr)
{
return ((addr->s_addr & 0xf0000000) == 0xe0000000);
}
static int process_via(struct sip_pvt *p, const struct sip_request *req)
{
struct sip_via *via = parse_via(get_header(req, "Via"));
if (!via) {
ast_log(LOG_ERROR, "error processing via header\n");
return -1;
}
if (via->maddr) {
struct hostent *hp;
struct ast_hostent ahp;
hp = ast_gethostbyname(via->maddr, &ahp);
if (hp == NULL) {
ast_log(LOG_WARNING, "Can't find address for maddr '%s'\n", via->maddr);
ast_log(LOG_ERROR, "error processing via header\n");
free_via(via);
return -1;
}
p->sa.sin_family = AF_INET;
memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr));
if (via->port) {
p->sa.sin_port = via->port;
} else {
p->sa.sin_port = STANDARD_SIP_PORT;
}
if (addr_is_multicast(&p->sa.sin_addr)) {
setsockopt(sipsock, IPPROTO_IP, IP_MULTICAST_TTL, &via->ttl, sizeof(via->ttl));
}
}
free_via(via);
return 0;
}
/*! \brief Connect incoming SIP message to current dialog or create new dialog structure
Called by handle_request, sipsock_read */
static struct sip_pvt *find_call(struct sip_request *req, struct sockaddr_in *sin, const int intended_method)
@ -6592,6 +6776,16 @@ static int respprep(struct sip_request *resp, struct sip_pvt *p, const char *msg
} else if (!ast_strlen_zero(p->our_contact) && resp_needs_contact(msg, p->method)) {
add_header(resp, "Contact", p->our_contact);
}
/* default to routing the response to the address where the request
* came from. Since we don't have a transport layer, we do this here.
*/
p->sa = p->recv;
if (process_via(p, req)) {
ast_log(LOG_WARNING, "error processing via header, will send response to originating address\n");
}
return 0;
}

Loading…
Cancel
Save