registrar.c

Go to the documentation of this file.
00001 /*
00002  * $Id: registrar.c 572 2008-07-15 13:46:27Z vingarzan $
00003  *  
00004  * Copyright (C) 2004-2006 FhG Fokus
00005  *
00006  * This file is part of Open IMS Core - an open source IMS CSCFs & HSS
00007  * implementation
00008  *
00009  * Open IMS Core is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * For a license to use the Open IMS Core software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact Fraunhofer FOKUS by e-mail at the following
00017  * addresses:
00018  *     info@open-ims.org
00019  *
00020  * Open IMS Core is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  * 
00025  * It has to be noted that this Open Source IMS Core System is not 
00026  * intended to become or act as a product in a commercial context! Its 
00027  * sole purpose is to provide an IMS core reference implementation for 
00028  * IMS technology testing and IMS application prototyping for research 
00029  * purposes, typically performed in IMS test-beds.
00030  * 
00031  * Users of the Open Source IMS Core System have to be aware that IMS
00032  * technology may be subject of patents and licence terms, as being 
00033  * specified within the various IMS-related IETF, ITU-T, ETSI, and 3GPP
00034  * standards. Thus all Open IMS Core users have to take notice of this 
00035  * fact and have to agree to check out carefully before installing, 
00036  * using and extending the Open Source IMS Core System, if related 
00037  * patents and licences may become applicable to the intended usage 
00038  * context.  
00039  *
00040  * You should have received a copy of the GNU General Public License
00041  * along with this program; if not, write to the Free Software
00042  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00043  * 
00044  */
00045  
00056 #include <time.h>
00057 
00058 #include "../../parser/contact/contact.h"
00059 #include "../../parser/contact/parse_contact.h"
00060 #include "../../ut.h"
00061 #include "../tm/tm_load.h"
00062 #include "../../dset.h"
00063 
00064 #include "registrar.h"
00065 #include "registrar_subscribe.h"
00066 #include "mod.h"
00067 #include "sip.h"
00068 #include "nat_helper.h"
00069 #include "security.h"
00070 #include "ims_pm.h"
00071 
00072 
00073 extern struct tm_binds tmb;             
00074 extern time_t time_now;                 
00075 extern r_hash_slot *registrar;          
00076 extern int     r_hash_size;             
00077 extern int pcscf_nat_enable;            
00078 extern int pcscf_nat_ping;              
00079 extern int pcscf_nat_pingall;           
00080 extern int pcscf_nat_detection_type;    
00082 #ifdef WITH_IMS_PM
00083     static str zero={0,0};
00084 #endif
00085 
00091 void registrar_timer(unsigned int ticks, void* param)
00092 {
00093     r_contact *c,*cn;
00094     int i;
00095     #ifdef WITH_IMS_PM
00096         int impu_cnt=0,contact_cnt=0,ipsec_cnt=0,tls_cnt=0,nat_cnt=0;
00097         r_public *rp;
00098     #endif
00099     
00100     LOG(L_DBG,"DBG:"M_NAME":registrar_timer: Called at %d\n",ticks);
00101     if (!registrar) registrar = (r_hash_slot*)param;
00102 
00103     r_act_time();
00104     
00105     for(i=0;i<r_hash_size;i++){
00106         r_lock(i);
00107             c = registrar[i].head;
00108             while(c){
00109                 cn = c->next;
00110                 switch (c->reg_state){
00111                     case NOT_REGISTERED:
00112                         LOG(L_DBG,"DBG:"M_NAME":registrar_timer: Contact <%.*s> Not Registered and removed.\n",
00113                                 c->uri.len,c->uri.s);
00114                         del_r_contact(c);
00115                         break;
00116                     case REGISTERED:
00117                         if (c->expires<=time_now) {
00118                             LOG(L_DBG,"DBG:"M_NAME":registrar_timer: Contact <%.*s> expired and Deregistered.\n",
00119                                 c->uri.len,c->uri.s);       
00120                             if (c->security){
00121                                 /* If we have IPSec SAs, we keep them 60 seconds more to relay further messages */
00122                                 c->reg_state = DEREGISTERED;
00123                                 c->expires = time_now + 60;
00124                             }else{
00125                                 LOG(L_DBG,"DBG:"M_NAME":registrar_timer: Contact <%.*s> expired and removed.\n",
00126                                     c->uri.len,c->uri.s);                       
00127                                 del_r_contact(c);
00128                             }
00129                         }
00130                         #ifdef WITH_IMS_PM
00131                             else {
00132                                     contact_cnt++;
00133                                     for(rp=c->head;rp;rp=rp->next)
00134                                         impu_cnt++;
00135                                     if (c->security && c->security->type==SEC_IPSEC) ipsec_cnt++;
00136                                     if (c->security && c->security->type==SEC_TLS) tls_cnt++;               
00137                                     if (c->pinhole) nat_cnt++;
00138                             }           
00139                         #endif
00140                         break;
00141                     case DEREGISTERED:
00142                         if (c->expires<=time_now) {
00143                             LOG(L_DBG,"DBG:"M_NAME":registrar_timer: Contact <%.*s> expired and removed.\n",
00144                                 c->uri.len,c->uri.s);       
00145                             P_security_drop(c,c->security);
00146                             P_security_drop(c,c->security_temp);
00147                             del_r_contact(c);
00148                         }
00149                         break;
00150                     case REG_PENDING:
00151                         if (c->expires<=time_now) {
00152                             LOG(L_DBG,"DBG:"M_NAME":registrar_timer: Contact <%.*s> Registration pending expired and removed.\n",
00153                                 c->uri.len,c->uri.s);       
00154                             P_security_drop(c,c->security);
00155                             P_security_drop(c,c->security_temp);
00156                             del_r_contact(c);
00157                         }
00158                         break;
00159                 }               
00160                 if (pcscf_nat_enable && pcscf_nat_ping) nat_send_ping(c);
00161                 c = cn;
00162             }
00163         r_unlock(i);
00164     }
00165     print_r(L_INFO);
00166     #ifdef WITH_IMS_PM
00167         IMS_PM_LOG01(RD_NbrContact,contact_cnt);
00168         IMS_PM_LOG01(RD_NbrIMPU,impu_cnt);
00169         IMS_PM_LOG01(RD_NbrIPSecSA,ipsec_cnt);
00170         IMS_PM_LOG01(RD_NbrTLSSA,tls_cnt);
00171         IMS_PM_LOG01(RD_NbrNATPinHoles,nat_cnt);
00172     #endif
00173 }
00174 
00175 
00187 static inline int r_calc_expires(contact_t *c,int expires_hdr, int local_time_now)
00188 {
00189     unsigned int r;
00190     if (expires_hdr>=0) r = expires_hdr;
00191     if (c) 
00192         str2int(&(c->expires->body), (unsigned int*)&r);
00193         
00194     return local_time_now+r;
00195 }
00196 
00197 
00211 static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl,unsigned char is_star,int expires_hdr,
00212     str *public_id,int public_id_cnt,str *service_route,int service_route_cnt, int requires_nat)
00213 {
00214     r_contact *rc;
00215     enum Reg_States reg_state=REGISTERED;
00216     int expires=0;
00217     int is_default=0,i;
00218     struct sip_uri puri;
00219     int max_expires=-1;
00220     int local_time_now;
00221     struct hdr_field *h;
00222     contact_t *c;
00223     r_nat_dest *pinhole;
00224     
00225     
00226     r_act_time();
00227     local_time_now = time_now;
00228     if (is_star){
00229         /* first of all, we shouldn't get here...
00230          * then, we will update on NOTIFY */
00231         return 0;
00232     }   
00233     for(h=rpl->contact;h;h=h->next)
00234         if (h->type==HDR_CONTACT_T && h->parsed)
00235          for(c=((contact_body_t*)h->parsed)->contacts;c;c=c->next){
00236             LOG(L_DBG,"DBG:"M_NAME":update_contact: <%.*s>\n",c->uri.len,c->uri.s);
00237             
00238             expires = r_calc_expires(c,expires_hdr,local_time_now);
00239             
00240             if (parse_uri(c->uri.s,c->uri.len,&puri)<0){
00241                 LOG(L_DBG,"DBG:"M_NAME":update_contact: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s);
00242                 continue;           
00243             }
00244             if (puri.port_no==0) puri.port_no=5060;
00245             LOG(L_DBG,"DBG:"M_NAME":update_contact: %d %.*s : %d\n",
00246                 puri.proto, puri.host.len,puri.host.s,puri.port_no);
00247             
00248             if (expires>local_time_now) {
00249                 if (requires_nat) {     
00250                     pinhole = nat_msg_origin(req);
00251                     rc = update_r_contact(puri.host,puri.port_no,puri.proto,
00252                         &(c->uri),&reg_state,&expires,&service_route,&service_route_cnt, &pinhole);
00253                 }else{
00254                     rc = update_r_contact(puri.host,puri.port_no,puri.proto,
00255                         &(c->uri),&reg_state,&expires,&service_route,&service_route_cnt, 0);
00256                 }
00257                 if (expires-time_now>max_expires) max_expires=expires-time_now;
00258             }
00259             else {
00260                 reg_state = DEREGISTERED;
00261                 expires = local_time_now+30;
00262                 rc = update_r_contact(puri.host,puri.port_no,puri.proto,
00263                         0,&reg_state,&expires,0,0,0);
00264                 if (rc) r_unlock(rc->hash);
00265                 if (0>max_expires) max_expires = 0;
00266                 rc = 0;
00267             }
00268             
00270             if (rc){
00271                 is_default=1;
00272                 if (public_id_cnt){
00273                     update_r_public(rc,public_id[0],&is_default);
00274                     is_default=0;
00275                     for(i=1;i<public_id_cnt;i++)
00276                         update_r_public(rc,public_id[i],&is_default);
00277                 }
00278                 r_unlock(rc->hash);
00279             }
00280     }
00281     return max_expires;
00282 }
00283 
00284 
00285 
00286 
00294 int P_save_location(struct sip_msg *rpl,char *str1, char *str2)
00295 {
00296     struct sip_msg *req;
00297     contact_body_t* b=0;    
00298     str realm;
00299     int expires_hdr=0;
00300     str *public_id=0;
00301     int public_id_cnt=0;
00302     int expires;
00303     str *service_route=0;
00304     int service_route_cnt;
00305         
00306     req = cscf_get_request_from_reply(rpl);
00307     if (!req){
00308         LOG(L_ERR,"ERR:"M_NAME":P_save_location: No transactional request found.\n");
00309         goto error;
00310     }
00311     
00312     expires_hdr = cscf_get_expires_hdr(rpl);
00314 //  if (expires_hdr<0) 
00315 //      expires_hdr = cscf_get_expires_hdr(req);
00316     
00317     if (parse_headers(rpl, HDR_EOH_F, 0) <0) {
00318         LOG(L_ERR,"ERR:"M_NAME":r_save_location: error parsing headers\n");
00319         return CSCF_RETURN_ERROR;
00320     }   
00321     
00322     b = cscf_parse_contacts(rpl);
00323     
00324     if (!b||(!b->contacts && !b->star)) {
00325         LOG(L_DBG,"DBG:"M_NAME":r_save_location: No contacts found\n");
00326         return 0;
00327     }
00328     
00329     realm = cscf_get_realm(req);
00330     
00331     cscf_get_p_associated_uri(rpl,&public_id,&public_id_cnt);
00332     
00333     service_route = cscf_get_service_route(rpl,&service_route_cnt);
00334             
00335     if ((expires=update_contacts(req,rpl,b->star,expires_hdr,public_id,public_id_cnt,service_route,service_route_cnt,requires_nat(req)))<0) 
00336         goto error;
00337 
00338     //print_r(L_ERR);
00339     
00340     
00341     if (service_route)  pkg_free(service_route);
00342     if (public_id) pkg_free(public_id);
00343     return CSCF_RETURN_TRUE;
00344 error:
00345     if (service_route)  pkg_free(service_route);
00346     if (public_id) pkg_free(public_id);
00347     return CSCF_RETURN_ERROR;
00348 }
00349 
00350 
00360 int r_is_integrity_protected(str host,int port,int r_port,int transport, unsigned long session_hash)
00361 {
00362     int ret=0;
00363     r_contact *c;
00364 
00365     if (port==0) port=5060;
00366 //  LOG(L_ERR,"DBG:"M_NAME":r_is_registered: Looking if registered <%d://%.*s:%d>\n",
00367 //      transport,host.len,host.s,port);
00368 
00369 //  print_r(L_INFO);
00370     c = get_r_contact(host,port,transport);
00371 
00372     if (!c) return 0;
00373     
00374     if (c->security){
00375         switch (c->security->type){
00376             case SEC_NONE:
00377                 break;
00378             case SEC_TLS:
00379                 if (c->security->data.tls&& 
00380                     (c->security->data.tls->port_tls==r_port) &&
00381                     (session_hash!= 0 && c->security->data.tls->session_hash == session_hash) // test same session
00382                     ){
00383                     ret = 1;
00384                 }
00385                 break;
00386             case SEC_IPSEC:
00387                 if (c->security->data.ipsec&&
00388                     (c->security->data.ipsec->port_uc==port || c->security->data.ipsec->port_us==port)){
00389                     ret = 1;
00390                 }
00391                 break;
00392         }           
00393     }
00394     if (!ret && c->security_temp){
00395         switch (c->security_temp->type){
00396             case SEC_NONE:
00397                 break;
00398             case SEC_TLS:
00399                 //nothing to do here becaues TLS security in temp does not mean that the user knows the password!
00400                 break;
00401             case SEC_IPSEC:
00402                 if (c->security_temp->data.ipsec&&
00403                     (c->security_temp->data.ipsec->port_uc==port || c->security_temp->data.ipsec->port_us==port)){
00404                     ret = 1;
00405                 }
00406                 break;
00407         }           
00408     }
00409     r_unlock(c->hash);
00410     return ret;
00411 }
00412 
00420 int r_is_registered(str host,int port,int transport)
00421 {
00422     int ret=0;
00423     r_contact *c;
00424 
00425     if (port==0) port=5060;
00426 //  LOG(L_ERR,"DBG:"M_NAME":r_is_registered: Looking if registered <%d://%.*s:%d>\n",
00427 //      transport,host.len,host.s,port);
00428 
00429 //  print_r(L_INFO);
00430     c = get_r_contact(host,port,transport);
00431 
00432     if (!c){        
00433         return 0;
00434     }   
00435     r_act_time();
00436     if (r_reg_contact(c)){
00437         ret = 1;
00438     }
00439     r_unlock(c->hash);
00440     
00441     return ret;
00442 }
00443 
00444 
00453 name_addr_t r_assert_identity(str host,int port,int transport,name_addr_t preferred)
00454 {
00455     r_contact *c;
00456     r_public *p;
00457     name_addr_t id;
00458     if (port==0) port=5060;
00459 
00460     memset(&id,0,sizeof(name_addr_t));
00461     
00462     LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: Asserting preferred id <%.*s>\n",
00463         preferred.uri.len,preferred.uri.s);
00464 //  print_r(L_INFO);
00465     c = get_r_contact(host,port,transport);
00466 
00467     if (!c){
00468         LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: Contact not found\n");       
00469         return id;
00470     }
00471     r_act_time();
00472     if (!r_reg_contact(c)){
00473         LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: Contact expired\n");
00474         r_unlock(c->hash);  
00475         return id;
00476     }
00477     
00478     if (!c->head){
00479         LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: No public ids for this user\n");
00480         r_unlock(c->hash);
00481         return id;  
00482     }
00483     id.name = preferred.name;   
00484     if (!preferred.uri.len){
00485         p = c->head;
00486         while(p&&!p->is_default)
00487             p = p->next;
00488         if (p) {
00489             LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: to <%.*s>\n",p->aor.len,p->aor.s);
00490             id.uri=p->aor;
00491             r_unlock(c->hash);
00492             return id;
00493         } else {
00494             LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: to <%.*s>\n",c->head->aor.len,c->head->aor.s);
00495             id.uri=c->head->aor;
00496             r_unlock(c->hash);
00497             return id;  
00498         }
00499     }else{
00500         p = c->head;
00501         while(p){
00502             if (p->aor.len==preferred.uri.len &&
00503                 strncasecmp(p->aor.s,preferred.uri.s,preferred.uri.len)==0)
00504             {
00505                 LOG(L_DBG,"DBG:"M_NAME":r_assert_identity: to <%.*s>\n",p->aor.len,p->aor.s);
00506                 id.uri = preferred.uri;
00507                 r_unlock(c->hash);
00508                 return id;                  
00509             }
00510             p = p->next;
00511         }
00512     }
00513     r_unlock(c->hash);
00514     return id;
00515 }
00516 
00517 
00518 
00519 
00520 

Generated on Thu Oct 23 04:14:38 2008 for Open IMS Core CSCFs by  doxygen 1.5.2