Skip to content

Commit

Permalink
fix: sip route/record-route uri parse error
Browse files Browse the repository at this point in the history
  • Loading branch information
ireader committed Jan 28, 2024
1 parent 043853e commit 8bc32a5
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 11 deletions.
4 changes: 4 additions & 0 deletions libsip/include/sip-header.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ int sip_header_vias(const char* s, const char* end, struct sip_vias_t* vias);
int sip_via_write(const struct sip_via_t* via, char* data, const char* end);
const struct cstring_t* sip_vias_top_branch(const struct sip_vias_t* vias);

int sip_header_route(const char* s, const char* end, struct sip_uri_t* route);
int sip_header_routes(const char* s, const char* end, struct sip_uris_t* route);
int sip_route_write(const struct sip_uri_t* route, char* data, const char* end);

int sip_header_contact(const char* s, const char* end, struct sip_contact_t* contact);
int sip_header_contacts(const char* s, const char* end, struct sip_contacts_t* contacts);
int sip_contact_write(const struct sip_contact_t* contact, char* data, const char* end);
Expand Down
1 change: 1 addition & 0 deletions libsip/libsip.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<ClCompile Include="src\header\sip-header-contact.c" />
<ClCompile Include="src\header\sip-header-param.c" />
<ClCompile Include="src\header\sip-header-cseq.c" />
<ClCompile Include="src\header\sip-header-route.c" />
<ClCompile Include="src\header\sip-header-substate.c" />
<ClCompile Include="src\header\sip-header-uri.c" />
<ClCompile Include="src\header\sip-header-via.c" />
Expand Down
3 changes: 3 additions & 0 deletions libsip/libsip.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,8 @@
<ClCompile Include="src\uas\sip-uas-prack.c">
<Filter>Source Files\uas</Filter>
</ClCompile>
<ClCompile Include="src\header\sip-header-route.c">
<Filter>SIP Header</Filter>
</ClCompile>
</ItemGroup>
</Project>
140 changes: 140 additions & 0 deletions libsip/src/header/sip-header-route.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// RFC3261 20.30 Record-Route / 20.43 Route
// Record-Route: <sip:p1.example.com;lr>
// Route: <sip:p1.example.com;lr>,<sip:p2.domain.com;lr>

/*
Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
rec-route = name-addr *( SEMI rr-param )
rr-param = generic-param
Route = "Route" HCOLON route-param *(COMMA route-param)
route-param = name-addr *( SEMI rr-param )
name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
addr-spec = SIP-URI / SIPS-URI / absoluteURI
*/

#include "sip-header.h"
#include <stdlib.h>
#include <ctype.h>

int sip_header_route(const char* s, const char* end, struct sip_uri_t* uri)
{
const char* p;

p = (s && s < end) ? strpbrk(s, "<\"") : NULL;
if (!p || p > end)
{
// addr-spec only
return sip_header_uri(s, end, uri);
}

if ('"' == *p)
{
// name-addr: [ display-name ]
p = strchr(p + 1, '"');
if (!p || p > end)
return -EINVAL;

// LAQUOT addr-spec RAQUOT
p = strchr(p + 1, '<');
if (!p || p > end)
return -EINVAL;
}

if ('<' == *p)
{
s = p + 1;
p = s < end ? strchr(s, '>') : NULL;
if (!p || p > end)
return -EINVAL;
}

return sip_header_uri(s, p, uri);
}

int sip_header_routes(const char* s, const char* end, struct sip_uris_t* routes)
{
int r;
const char* p;
struct sip_uri_t c;

for (r = 0; 0 == r && s && s < end; s = p + 1)
{
// filter ","
p = strpbrk(s, ",\"");
while (p && p + 1 < end && '"' == *p)
{
p = strchr(p + 1, '"');
if (p && p < end)
p = strpbrk(p + 1, ",\"");
}
if (!p || p >= end)
p = end;

r = sip_header_route(s, p, &c);
if (0 == r)
r = sip_uris_push(routes, &c);
}

return r;
}

// Route: <sip:p1.example.com;lr>,<sip:p2.domain.com;lr>
int sip_route_write(const struct sip_uri_t* route, char* data, const char* end)
{
int n;
char* p;

p = data;
if (p < end) *p++ = '<';
n = sip_uri_write(route, p, end);
if (n < 0) return n;
p += n;
if (p < end) *p++ = '>';

if (p < end) *p = '\0';
return (int)(p - data);
}

#if defined(DEBUG) || defined(_DEBUG)
void sip_header_route_test(void)
{
char p[1024];
const char* s;
const struct sip_uri_t* c;
struct sip_uri_t route;
struct sip_uris_t routes;

sip_uris_init(&routes);
s = "\"Mr.Watson\" <sip:[email protected]>;q=0.7; expires=3600,\"Mr.Watson\" <mailto:[email protected]> ;q=0.1";
assert(0 == sip_header_routes(s, s + strlen(s), &routes) && 2 == sip_uris_count(&routes));
c = sip_uris_get(&routes, 0);
assert(0 == cstrcmp(&c->scheme, "sip") && 0 == cstrcmp(&c->host, "[email protected]") && 0 == sip_params_count(&c->headers) && 0 == sip_params_count(&c->parameters));
c = sip_uris_get(&routes, 1);
assert(0 == cstrcmp(&c->scheme, "mailto") && 0 == cstrcmp(&c->host, "[email protected]") && 0 == sip_params_count(&c->headers) && 0 == sip_params_count(&c->parameters));
sip_uris_free(&routes);

s = "<sips:[email protected]>;expires=60";
assert(0 == sip_header_route(s, s + strlen(s), &route));
assert(0 == cstrcmp(&route.scheme, "sips") && 0 == cstrcmp(&route.host, "[email protected]") && 0 == sip_params_count(&route.headers) && 0 == sip_params_count(&route.parameters));
assert(sip_route_write(&route, p, p + sizeof(p)) < sizeof(p) && 0 == strncmp(s, p, 20));
sip_uri_free(&route);

s = "\"<sip:[email protected]>\" <sip:[email protected]>";
assert(0 == sip_header_route(s, s + strlen(s), &route));
assert(0 == cstrcmp(&route.scheme, "sip") && 0 == cstrcmp(&route.host, "[email protected]") && 0 == sip_params_count(&route.headers) && 0 == sip_params_count(&route.parameters));
assert(sip_route_write(&route, p, p + sizeof(p)) < sizeof(p) && 0 == strcmp(s+20, p));
sip_uri_free(&route);

s = "<sip:p1.example.com;lr>,<sip:p2.domain.com;lr>";
sip_uris_init(&routes);
assert(0 == sip_header_routes(s, s + strlen(s), &routes) && 2 == sip_uris_count(&routes));
c = sip_uris_get(&routes, 0);
assert(0 == cstrcmp(&c->scheme, "sip") && 0 == cstrcmp(&c->host, "p1.example.com") && 0 == sip_params_count(&c->headers) && 1 == sip_params_count(&c->parameters));
assert(0 == cstrcmp(&sip_params_get(&c->parameters, 0)->name, "lr") && c->lr);
c = sip_uris_get(&routes, 1);
assert(0 == cstrcmp(&c->scheme, "sip") && 0 == cstrcmp(&c->host, "p2.domain.com") && 0 == sip_params_count(&c->headers) && 1 == sip_params_count(&c->parameters));
assert(0 == cstrcmp(&sip_params_get(&c->parameters, 0)->name, "lr") && c->lr);
//assert(sip_route_write(c, p, p + sizeof(p)) < sizeof(p) && 0 == strcmp(s, p));
sip_uris_free(&routes);
}
#endif
16 changes: 5 additions & 11 deletions libsip/src/sip-message.c
Original file line number Diff line number Diff line change
Expand Up @@ -567,14 +567,14 @@ static char* sip_message_routers(const struct sip_message_t* msg, char* p, const
for (i = strict_router; i < sip_uris_count((struct sip_uris_t*)&msg->routers) && p < end; i++)
{
if (p < end) p += snprintf(p, end - p, "\r\n%s: ", SIP_HEADER_ROUTE);
if (p < end) p += sip_uri_write(sip_uris_get((struct sip_uris_t*)&msg->routers, i), p, end);
if (p < end) p += sip_route_write(sip_uris_get((struct sip_uris_t*)&msg->routers, i), p, end);
}

// place the remote target URI into the Route header field as the last value
if (strict_router)
{
if (p < end) p += snprintf(p, end - p, "\r\n%s: ", SIP_HEADER_ROUTE);
if (p < end) p += sip_uri_write(&msg->u.c.uri, p, end);
if (p < end) p += sip_route_write(&msg->u.c.uri, p, end);
}

return p;
Expand Down Expand Up @@ -630,7 +630,7 @@ int sip_message_write(const struct sip_message_t* msg, uint8_t* data, int bytes)
for (i = 0; i < sip_uris_count((struct sip_uris_t*)&msg->record_routers); i++)
{
if (p < end) p += snprintf(p, end - p, "\r\n%s: ", SIP_HEADER_RECORD_ROUTE);
if (p < end) p += sip_uri_write(sip_uris_get((struct sip_uris_t*)&msg->record_routers, i), p, end);
if (p < end) p += sip_route_write(sip_uris_get((struct sip_uris_t*)&msg->record_routers, i), p, end);
}

// PRACK
Expand Down Expand Up @@ -758,17 +758,11 @@ int sip_message_add_header(struct sip_message_t* msg, const char* name, const ch
}
else if (0 == strcasecmp(SIP_HEADER_ROUTE, name))
{
memset(&uri, 0, sizeof(uri));
r = sip_header_uri(header.value.p, header.value.p + header.value.n, &uri);
if (0 == r)
sip_uris_push(&msg->routers, &uri);
r = sip_header_routes(header.value.p, header.value.p + header.value.n, &msg->routers);
}
else if (0 == strcasecmp(SIP_HEADER_RECORD_ROUTE, name))
{
memset(&uri, 0, sizeof(uri));
r = sip_header_uri(header.value.p, header.value.p + header.value.n, &uri);
if (0 == r)
sip_uris_push(&msg->record_routers, &uri);
r = sip_header_routes(header.value.p, header.value.p + header.value.n, &msg->record_routers);
}
else if (0 == strcasecmp(SIP_HEADER_RECV_INFO, name))
{
Expand Down
2 changes: 2 additions & 0 deletions libsip/test/sip-header-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ void sip_header_param_test(void);
void sip_uri_parse_test(void);
void sip_uri_equal_test(void);
void sip_header_contact_test(void);
void sip_header_route_test(void);
void sip_header_via_test(void);
void sip_header_cseq_test(void);
void sip_header_substate_test(void);
Expand All @@ -13,6 +14,7 @@ void sip_header_test(void)
sip_uri_parse_test();
sip_uri_equal_test();
sip_header_contact_test();
sip_header_route_test();
sip_header_via_test();
sip_header_cseq_test();
sip_header_substate_test();
Expand Down
5 changes: 5 additions & 0 deletions libsip/test/sip-message-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ static int sip_test_invite(struct sip_message_test_t* alice, struct sip_message_
"Max-Forwards: 70\r\n"
"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8;received=192.0.2.1\r\n"
"Contact: <sip:[email protected]>\r\n"
"Record-Route: <sip:[email protected];lr>\r\n"
"Content-Length: 0\r\n\r\n";

// F8 180 Ringing atlanta.com proxy -> Alice (217)
Expand All @@ -234,6 +235,7 @@ static int sip_test_invite(struct sip_message_test_t* alice, struct sip_message_
"Max-Forwards: 70\r\n"
"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8;received=192.0.2.1\r\n"
"Contact: <sip:[email protected]>\r\n"
"Record-Route: <sip:[email protected];lr>\r\n"
"Content-Length: 0\r\n\r\n";

// F11 200 OK atlanta.com proxy -> Alice (p218)
Expand All @@ -245,6 +247,7 @@ static int sip_test_invite(struct sip_message_test_t* alice, struct sip_message_
"Max-Forwards: 70\r\n"
"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8;received=192.0.2.1\r\n"
"Contact: <sip:[email protected]>\r\n"
"Record-Route: <sip:[email protected];lr>\r\n"
//"Content-Type: application/sdp\r\n"
"Content-Length: 0\r\n\r\n";

Expand All @@ -256,6 +259,7 @@ static int sip_test_invite(struct sip_message_test_t* alice, struct sip_message_
"CSeq: 314159 ACK\r\n"
"Max-Forwards: 70\r\n"
"Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds9\r\n"
"Route: <sip:[email protected];lr>\r\n"
"Content-Length: 0\r\n\r\n";

const char* f13 = "SIP/2.0 603 Decline\r\n"
Expand Down Expand Up @@ -284,6 +288,7 @@ static int sip_test_invite(struct sip_message_test_t* alice, struct sip_message_
assert(0 == sip_agent_input(bob->sip, req, bob));
sip_message_add_header(bob->st->reply, "To", "Bob <sip:[email protected]>;tag=a6c85cf"); // modify to.tag
sip_message_add_header(bob->st->reply, "Contact", "<sip:[email protected]>");
sip_message_add_header(bob->st->reply, "Record-Route", "<sip:[email protected];lr>");
assert(0 == sip_uas_reply(bob->st.get(), 100, NULL, 0, bob) && 0 == strcmp(bob->buf, f2));
assert(0 == sip_agent_input(alice->sip, reply100, alice));
assert(0 == sip_uas_reply(bob->st.get(), 180, NULL, 0, bob) && 0 == strcmp(bob->buf, f8));
Expand Down

0 comments on commit 8bc32a5

Please sign in to comment.