- deal with wildcard Contact header for unREGISTER

This commit is contained in:
Thomas Ries
2004-03-22 18:44:34 +00:00
parent b2ef7599c8
commit ff23e0862d
3 changed files with 293 additions and 139 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 ... */