- deal with wildcard Contact header for unREGISTER
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
0.5.5
|
||||
=====
|
||||
22-Mar-2004: - deal with wildcard Contact header for unREGISTER
|
||||
21-Mar-2004: - added ./autogen.sh
|
||||
- security_check_sip: check existence of mandatory headers
|
||||
19-Mar-2004: - proxy_rewrite_invitation_body: check success of
|
||||
starting RTP relay before rewriting SDP body
|
||||
- proxy_rewrite_invitation_body: don't fail on
|
||||
|
||||
278
src/register.c
278
src/register.c
@@ -171,7 +171,7 @@ int register_client(osip_message_t *my_msg, int force_lcl_masq) {
|
||||
int expires;
|
||||
time_t time_now;
|
||||
osip_uri_t *url1_to, *url1_contact;
|
||||
osip_uri_t *url2_to, *url2_contact;
|
||||
osip_uri_t *url2_to;
|
||||
osip_header_t *expires_hdr;
|
||||
osip_uri_param_t *expires_param=NULL;
|
||||
|
||||
@@ -205,6 +205,9 @@ int register_client(osip_message_t *my_msg, int force_lcl_masq) {
|
||||
|
||||
To: -> address to be registered
|
||||
Contact: -> host is reachable there
|
||||
Note: in case of un-REGISTER, the contact header may
|
||||
contain '*' only - which means "all registrations
|
||||
made by this UA"
|
||||
|
||||
=> Mapping is
|
||||
To: <1--n> Contact
|
||||
@@ -246,134 +249,159 @@ int register_client(osip_message_t *my_msg, int force_lcl_masq) {
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
expires);
|
||||
|
||||
/* Update registration. There are two possibilities:
|
||||
* - already registered, then update the existing record
|
||||
* - not registered, then create a new record
|
||||
*/
|
||||
|
||||
j=-1;
|
||||
for (i=0; i<URLMAP_SIZE; i++) {
|
||||
if (urlmap[i].active == 0) {
|
||||
if (j < 0) j=i; /* remember first hole */
|
||||
continue;
|
||||
}
|
||||
|
||||
url2_to=urlmap[i].reg_url;
|
||||
url2_contact=urlmap[i].true_url;
|
||||
|
||||
if ( (compare_url(url1_to, url2_to)==STS_SUCCESS) &&
|
||||
(compare_url(url1_contact, url2_contact)==STS_SUCCESS) ) {
|
||||
DEBUGC(DBCLASS_REG, "found entry for %s@%s <-> %s@%s at "
|
||||
"slot=%i, exp=%li",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(url2_to->username) ? url2_to->username : "*NULL*",
|
||||
(url2_to->host) ? url2_to->host : "*NULL*",
|
||||
i, urlmap[i].expires-time_now);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (j < 0) && (i >= URLMAP_SIZE) ) {
|
||||
/* oops, no free entries left... */
|
||||
ERROR("URLMAP is full - registration failed");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
if (i >= URLMAP_SIZE) {
|
||||
/* entry not existing, create new one */
|
||||
i=j;
|
||||
|
||||
/* write entry */
|
||||
urlmap[i].active=1;
|
||||
/* Contact: field */
|
||||
osip_uri_clone( ((osip_contact_t*)(my_msg->contacts->node->element))->url,
|
||||
&urlmap[i].true_url);
|
||||
/* To: field */
|
||||
osip_uri_clone( my_msg->to->url,
|
||||
&urlmap[i].reg_url);
|
||||
|
||||
DEBUGC(DBCLASS_REG,"create new entry for %s@%s <-> %s@%s at slot=%i",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(urlmap[i].reg_url->username) ? urlmap[i].reg_url->username : "*NULL*",
|
||||
(urlmap[i].reg_url->host) ? urlmap[i].reg_url->host : "*NULL*",
|
||||
i);
|
||||
|
||||
/*
|
||||
* try to figure out if we ought to do some masquerading
|
||||
*/
|
||||
osip_uri_clone( my_msg->to->url,
|
||||
&urlmap[i].masq_url);
|
||||
|
||||
n=configuration.mask_host.used;
|
||||
if (n != configuration.masked_host.used) {
|
||||
ERROR("# of mask_host is not equal to # of masked_host in config!");
|
||||
n=0;
|
||||
}
|
||||
|
||||
DEBUG("%i entries in MASK config table", n);
|
||||
for (j=0; j<n; j++) {
|
||||
DEBUG("compare [%s] <-> [%s]",configuration.mask_host.string[j],
|
||||
my_msg->to->url->host);
|
||||
if (strcmp(configuration.mask_host.string[j],
|
||||
my_msg->to->url->host)==0)
|
||||
break;
|
||||
}
|
||||
if (j<n) {
|
||||
/* we are masquerading this UA, replace the host part of the url */
|
||||
DEBUGC(DBCLASS_REG,"masquerading UA %s@%s as %s@%s",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
configuration.masked_host.string[j]);
|
||||
urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host,
|
||||
strlen(configuration.masked_host.string[j])+1);
|
||||
strcpy(urlmap[i].masq_url->host, configuration.masked_host.string[j]);
|
||||
}
|
||||
|
||||
/*
|
||||
* for transparent proxying: force device to be masqueraded
|
||||
* as with the outbound IP
|
||||
*/
|
||||
if (force_lcl_masq) {
|
||||
struct in_addr addr;
|
||||
char *addrstr;
|
||||
sts = get_ip_by_ifname(configuration.outbound_if,&addr);
|
||||
addrstr = utils_inet_ntoa(addr);
|
||||
DEBUGC(DBCLASS_REG,"masquerading UA %s@%s local %s@%s",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
addrstr);
|
||||
urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host,
|
||||
strlen(addrstr)+1);
|
||||
strcpy(urlmap[i].masq_url->host, addrstr);
|
||||
}
|
||||
|
||||
/* remember the VIA for later use */
|
||||
// osip_via_clone( ((osip_via_t*)(my_msg->vias->node->element)),
|
||||
// &urlmap[i].via);
|
||||
} else { /* if new entry */
|
||||
/*
|
||||
* Some phones (like BudgeTones *may* dynamically grab a SIP port
|
||||
* so we might want to update the true_url and reg_url each time
|
||||
* we get an REGISTER
|
||||
* REGISTER
|
||||
*/
|
||||
/* Contact: field */
|
||||
osip_uri_free(urlmap[i].true_url);
|
||||
osip_uri_clone( ((osip_contact_t*)(my_msg->contacts->node->element))->url,
|
||||
&urlmap[i].true_url);
|
||||
/* To: field */
|
||||
osip_uri_free(urlmap[i].reg_url);
|
||||
osip_uri_clone( my_msg->to->url,
|
||||
&urlmap[i].reg_url);
|
||||
}
|
||||
/* give some safety margin for the next update */
|
||||
if (expires > 0) expires+=30;
|
||||
if (expires > 0) {
|
||||
/* Update registration. There are two possibilities:
|
||||
* - already registered, then update the existing record
|
||||
* - not registered, then create a new record
|
||||
*/
|
||||
|
||||
/* update registration timeout */
|
||||
urlmap[i].expires=time_now+expires;
|
||||
j=-1;
|
||||
for (i=0; i<URLMAP_SIZE; i++) {
|
||||
if (urlmap[i].active == 0) {
|
||||
if (j < 0) j=i; /* remember first hole */
|
||||
continue;
|
||||
}
|
||||
|
||||
url2_to=urlmap[i].reg_url;
|
||||
|
||||
/* check address-of-record ("public address" of user) */
|
||||
if (compare_url(url1_to, url2_to)==STS_SUCCESS) {
|
||||
DEBUGC(DBCLASS_REG, "found entry for %s@%s <-> %s@%s at "
|
||||
"slot=%i, exp=%li",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(url2_to->username) ? url2_to->username : "*NULL*",
|
||||
(url2_to->host) ? url2_to->host : "*NULL*",
|
||||
i, urlmap[i].expires-time_now);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (j < 0) && (i >= URLMAP_SIZE) ) {
|
||||
/* oops, no free entries left... */
|
||||
ERROR("URLMAP is full - registration failed");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
if (i >= URLMAP_SIZE) {
|
||||
/* entry not existing, create new one */
|
||||
i=j;
|
||||
|
||||
/* write entry */
|
||||
urlmap[i].active=1;
|
||||
/* Contact: field */
|
||||
osip_uri_clone( ((osip_contact_t*)(my_msg->contacts->node->element))->url,
|
||||
&urlmap[i].true_url);
|
||||
/* To: field */
|
||||
osip_uri_clone( my_msg->to->url,
|
||||
&urlmap[i].reg_url);
|
||||
|
||||
DEBUGC(DBCLASS_REG,"create new entry for %s@%s <-> %s@%s at slot=%i",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(urlmap[i].reg_url->username) ? urlmap[i].reg_url->username : "*NULL*",
|
||||
(urlmap[i].reg_url->host) ? urlmap[i].reg_url->host : "*NULL*",
|
||||
i);
|
||||
|
||||
/*
|
||||
* try to figure out if we ought to do some masquerading
|
||||
*/
|
||||
osip_uri_clone( my_msg->to->url,
|
||||
&urlmap[i].masq_url);
|
||||
|
||||
n=configuration.mask_host.used;
|
||||
if (n != configuration.masked_host.used) {
|
||||
ERROR("# of mask_host is not equal to # of masked_host in config!");
|
||||
n=0;
|
||||
}
|
||||
|
||||
DEBUG("%i entries in MASK config table", n);
|
||||
for (j=0; j<n; j++) {
|
||||
DEBUG("compare [%s] <-> [%s]",configuration.mask_host.string[j],
|
||||
my_msg->to->url->host);
|
||||
if (strcmp(configuration.mask_host.string[j],
|
||||
my_msg->to->url->host)==0)
|
||||
break;
|
||||
}
|
||||
if (j<n) {
|
||||
/* we are masquerading this UA, replace the host part of the url */
|
||||
DEBUGC(DBCLASS_REG,"masquerading UA %s@%s as %s@%s",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
configuration.masked_host.string[j]);
|
||||
urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host,
|
||||
strlen(configuration.masked_host.string[j])+1);
|
||||
strcpy(urlmap[i].masq_url->host, configuration.masked_host.string[j]);
|
||||
}
|
||||
|
||||
/*
|
||||
* for transparent proxying: force device to be masqueraded
|
||||
* as with the outbound IP
|
||||
*/
|
||||
if (force_lcl_masq) {
|
||||
struct in_addr addr;
|
||||
char *addrstr;
|
||||
sts = get_ip_by_ifname(configuration.outbound_if,&addr);
|
||||
addrstr = utils_inet_ntoa(addr);
|
||||
DEBUGC(DBCLASS_REG,"masquerading UA %s@%s local %s@%s",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
(url1_contact->host) ? url1_contact->host : "*NULL*",
|
||||
(url1_contact->username) ? url1_contact->username : "*NULL*",
|
||||
addrstr);
|
||||
urlmap[i].masq_url->host=realloc(urlmap[i].masq_url->host,
|
||||
strlen(addrstr)+1);
|
||||
strcpy(urlmap[i].masq_url->host, addrstr);
|
||||
}
|
||||
|
||||
} else { /* if new entry */
|
||||
/*
|
||||
* Some phones (like BudgeTones *may* dynamically grab a SIP port
|
||||
* so we might want to update the true_url and reg_url each time
|
||||
* we get an REGISTER
|
||||
*/
|
||||
/* Contact: field */
|
||||
osip_uri_free(urlmap[i].true_url);
|
||||
osip_uri_clone( ((osip_contact_t*)(my_msg->contacts->node->element))->url,
|
||||
&urlmap[i].true_url);
|
||||
/* To: field */
|
||||
osip_uri_free(urlmap[i].reg_url);
|
||||
osip_uri_clone( my_msg->to->url,
|
||||
&urlmap[i].reg_url);
|
||||
}
|
||||
/* give some safety margin for the next update */
|
||||
if (expires > 0) expires+=30;
|
||||
|
||||
/* update registration timeout */
|
||||
urlmap[i].expires=time_now+expires;
|
||||
|
||||
/*
|
||||
* un-REGISTER
|
||||
*/
|
||||
} else { /* expires > 0 */
|
||||
/*
|
||||
* Remove registration
|
||||
* Siproxd will ALWAYS remove ALL bindings for a given
|
||||
* address-of-record
|
||||
*/
|
||||
for (i=0; i<URLMAP_SIZE; i++) {
|
||||
if (urlmap[i].active == 0) continue;
|
||||
|
||||
url2_to=urlmap[i].reg_url;
|
||||
|
||||
if (compare_url(url1_to, url2_to)==STS_SUCCESS) {
|
||||
DEBUGC(DBCLASS_REG, "removing registration for %s@%s at slot=%i",
|
||||
(url2_to->username) ? url2_to->username : "*NULL*",
|
||||
(url2_to->host) ? url2_to->host : "*NULL*", i);
|
||||
urlmap[i].expires=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
152
src/security.c
152
src/security.c
@@ -83,29 +83,153 @@ int security_check_sip(osip_message_t *sip){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check existence of mandatory headers
|
||||
*
|
||||
|
||||
/* check for existing To: header */
|
||||
if ((sip->to==NULL)||(sip->to->url==NULL)||(sip->to->url->host==NULL)) {
|
||||
ERROR("security check failed: NULL To Header");
|
||||
Rosenberg, et. al. Standards Track [Page 161]
|
||||
|
||||
RFC 3261 SIP: Session Initiation Protocol June 2002
|
||||
|
||||
Header field where proxy ACK BYE CAN INV OPT REG
|
||||
___________________________________________________________
|
||||
Accept R - o - o m* o
|
||||
Accept 2xx - - - o m* o
|
||||
Accept 415 - c - c c c
|
||||
Accept-Encoding R - o - o o o
|
||||
Accept-Encoding 2xx - - - o m* o
|
||||
Accept-Encoding 415 - c - c c c
|
||||
Accept-Language R - o - o o o
|
||||
Accept-Language 2xx - - - o m* o
|
||||
Accept-Language 415 - c - c c c
|
||||
Alert-Info R ar - - - o - -
|
||||
Alert-Info 180 ar - - - o - -
|
||||
Allow R - o - o o o
|
||||
Allow 2xx - o - m* m* o
|
||||
Allow r - o - o o o
|
||||
Allow 405 - m - m m m
|
||||
Authentication-Info 2xx - o - o o o
|
||||
Authorization R o o o o o o
|
||||
Call-ID c r m m m m m m
|
||||
Call-Info ar - - - o o o
|
||||
Contact R o - - m o o
|
||||
Contact 1xx - - - o - -
|
||||
Contact 2xx - - - m o o
|
||||
Contact 3xx d - o - o o o
|
||||
Contact 485 - o - o o o
|
||||
Content-Disposition o o - o o o
|
||||
Content-Encoding o o - o o o
|
||||
Content-Language o o - o o o
|
||||
Content-Length ar t t t t t t
|
||||
Content-Type * * - * * *
|
||||
CSeq c r m m m m m m
|
||||
Date a o o o o o o
|
||||
Error-Info 300-699 a - o o o o o
|
||||
Expires - - - o - o
|
||||
From c r m m m m m m
|
||||
In-Reply-To R - - - o - -
|
||||
Max-Forwards R amr m m m m m m
|
||||
Min-Expires 423 - - - - - m
|
||||
MIME-Version o o - o o o
|
||||
Organization ar - - - o o o
|
||||
|
||||
Table 2: Summary of header fields, A--O
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Rosenberg, et. al. Standards Track [Page 162]
|
||||
|
||||
RFC 3261 SIP: Session Initiation Protocol June 2002
|
||||
|
||||
|
||||
Header field where proxy ACK BYE CAN INV OPT REG
|
||||
___________________________________________________________________
|
||||
Priority R ar - - - o - -
|
||||
Proxy-Authenticate 407 ar - m - m m m
|
||||
Proxy-Authenticate 401 ar - o o o o o
|
||||
Proxy-Authorization R dr o o - o o o
|
||||
Proxy-Require R ar - o - o o o
|
||||
Record-Route R ar o o o o o -
|
||||
Record-Route 2xx,18x mr - o o o o -
|
||||
Reply-To - - - o - -
|
||||
Require ar - c - c c c
|
||||
Retry-After 404,413,480,486 - o o o o o
|
||||
500,503 - o o o o o
|
||||
600,603 - o o o o o
|
||||
Route R adr c c c c c c
|
||||
Server r - o o o o o
|
||||
Subject R - - - o - -
|
||||
Supported R - o o m* o o
|
||||
Supported 2xx - o o m* m* o
|
||||
Timestamp o o o o o o
|
||||
To c(1) r m m m m m m
|
||||
Unsupported 420 - m - m m m
|
||||
User-Agent o o o o o o
|
||||
Via R amr m m m m m m
|
||||
Via rc dr m m m m m m
|
||||
Warning r - o o o o o
|
||||
WWW-Authenticate 401 ar - m - m m m
|
||||
WWW-Authenticate 407 ar - o - o o o
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* => Mandatory for ALL requests and responses
|
||||
* Call-ID c r m m m m m m
|
||||
* CSeq c r m m m m m m
|
||||
* From c r m m m m m m
|
||||
* To c(1) r m m m m m m
|
||||
* Via R amr m m m m m m
|
||||
*/
|
||||
|
||||
/* check for existing Call-ID header */
|
||||
if ((sip->call_id==NULL)||
|
||||
((sip->call_id->number==NULL)&&(sip->call_id->host==NULL))) {
|
||||
ERROR("security check failed: NULL Call-Id Header");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/* check for existing FROM */
|
||||
if ((sip->from==NULL)||(sip->from->url==NULL)||(sip->from->url->host==NULL)) {
|
||||
ERROR("security check failed: NULL From Header");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/* check for existing CSEQ header */
|
||||
if ((sip->cseq==NULL)||(sip->cseq->method==NULL)||(sip->cseq->number==NULL)) {
|
||||
/* check for existing CSeq header */
|
||||
if ((sip->cseq==NULL)||
|
||||
(sip->cseq->method==NULL)||(sip->cseq->number==NULL)) {
|
||||
ERROR("security check failed: NULL CSeq Header");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/* check for existing To: header */
|
||||
if ((sip->to==NULL)||
|
||||
(sip->to->url==NULL)||(sip->to->url->host==NULL)) {
|
||||
ERROR("security check failed: NULL To Header");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
check the RFC and implement tests for ALL mandatory headers here
|
||||
*/
|
||||
/* check for existing From: header */
|
||||
if ((sip->from==NULL)||
|
||||
(sip->from->url==NULL)||(sip->from->url->host==NULL)) {
|
||||
ERROR("security check failed: NULL From Header");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/* check for existing Via: header list */
|
||||
if (sip->vias==NULL) {
|
||||
ERROR("security check failed: No Via Headers");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* check for existing Contact: header
|
||||
* according to RFC3261 not mandatory, but siproxd relies on it...
|
||||
*/
|
||||
if ((sip->contacts==NULL)||
|
||||
(sip->contacts->node==NULL)||(sip->contacts->node->element==NULL)||
|
||||
((osip_contact_t*)(sip->contacts->node->element))->url==NULL) {
|
||||
ERROR("security check failed: NULL Contact Header");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: still way to go here ... */
|
||||
|
||||
Reference in New Issue
Block a user