/** * Expires all the contacts for the given public id * @param public_id - public identity to expire contacts for */ void r_public_expire(str public_id) { int expire; r_public *r_pub; r_contact * r_cont ; r_act_time(); expire = time_now; r_pub = get_r_public(public_id); if (!r_pub){ LOG(L_ERR,"ERR:"M_NAME":set_expires: identity not found in registrar <%.*s>\n",public_id.len,public_id.s); return; } r_cont = r_pub->head; while(r_cont!=NULL){ r_cont->expires = expire; r_cont=r_cont->next; } r_unlock(r_pub->hash); print_r(L_ALERT); }
/** * Expires all the contacts of public identities that are related to the given private id * @param private_id - private identity to expire contacts for */ void r_private_expire(str private_id) { int expire,i; r_public *p; r_contact *c; r_act_time(); expire = time_now; for(i=0;i<r_hash_size;i++){ r_lock(i); for(p = registrar[i].head;p;p=p->next){ if (p->s){ lock_get(p->s->lock); if (p->s->private_identity.len == private_id.len && strncasecmp(p->s->private_identity.s,private_id.s,private_id.len)==0){ for(c=p->head;c;c=c->next) c->expires = expire; } lock_release(p->s->lock); } } r_unlock(i); } print_r(L_ALERT); }
void print_subs(int log_level) { r_subscription *s; int i; #ifdef SER_MOD_INTERFACE if (!is_printable(log_level)) #else if (debug<log_level) #endif return; /* to avoid useless calls when nothing will be printed */ LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list begin ---------\n"); for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; r_act_time(); while(s){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4u]\tP: <"ANSI_BLUE"%.*s"ANSI_GREEN"> D:["ANSI_CYAN"%5d"ANSI_GREEN"] E:["ANSI_MAGENTA"%5d"ANSI_GREEN"] Att:[%2d]\n", s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left); s = s->next; } subs_unlock(i); } LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list end -----------\n"); }
/** * Look if there are no more public ids or contacts registered and expires the subscription * \note must be called with lock on the domain * @param p - the r_public to update. * @returns the expiration is seconds */ static inline long r_update_subscription_status(r_public *p) { r_subscriber *s; r_contact *c; long expires=0; int cnt=0; r_act_time(); c = p->head; while(c){ if (r_valid_contact(c)){ if (c->expires-time_now+30>expires) expires = c->expires-time_now+30; cnt++; } c = c->next; } if (!cnt){ s = p->shead; while(s){ s->expires = time_now-1; s = s->next; } } return expires; }
/** * Processes a notification and updates the registrar info. * @param n - the notification * @param expires - the Subscription-Status expires parameter * @returns 1 on success, 0 on error */ int r_notification_process(r_notification *n,int expires) { r_registration *r; r_regcontact *rc; r_contact *c; struct sip_uri puri; enum Reg_States reg_state; int expires2; r_subscription *s=0; r_notification_print(n); if (!n) return 0; r_act_time(); r = n->registration; while(r){ rc = r->contact; while(rc){ if (parse_uri(rc->uri.s,rc->uri.len,&puri)<0){ LOG(L_ERR,"ERR:"M_NAME":r_notification_process: Error parsing Contact URI <%.*s>\n", rc->uri.len,rc->uri.s); goto next; } // LOG(L_CRIT,"DBG:"M_NAME":r_notification_process: refreshing contacts <%.*s> [%d]\n",rc->uri.len,rc->uri.s,rc->expires); if (rc->state==IMS_REGINFO_TERMINATED){ reg_state = DEREGISTERED; expires2 = time_now+30; c = update_r_contact(puri.host,puri.port_no,puri.proto, 0,®_state,&expires2,0,0,0); if (c) { LOG(L_DBG,"DBG:"M_NAME":r_notification_process: expired contact <%.*s>\n", c->uri.len,c->uri.s); r_unlock(c->hash); } }else{ reg_state = REGISTERED; expires2 = rc->expires+time_now; c = update_r_contact(puri.host,puri.port_no,puri.proto, 0,®_state,&expires2,0,0,0); if (c) { LOG(L_DBG,"DBG:"M_NAME":r_notification_process: refreshing contact <%.*s> [%d]\n", c->uri.len,c->uri.s,rc->expires); r_unlock(c->hash); } } next: rc = rc->next; } s = get_r_subscription(r->aor); if (s){ update_r_subscription(s,expires); subs_unlock(s->hash); } r = r->next; } return 1; }
/** * The Subscription timer looks for almost expired subscriptions and subscribes again. * @param ticks - the current time * @param param - the generic parameter */ void subscription_timer(unsigned int ticks, void* param) { r_subscription *s,*ns; int i; #ifdef WITH_IMS_PM int subs_cnt=0; #endif for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; r_act_time(); while(s){ ns = s->next; if (s->attempts_left > 0 ){ /* attempt to send a subscribe */ if (!r_send_subscribe(s,s->duration)){ LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE (%d times)... droping\n", pcscf_subscribe_retries); del_r_subscription_nolock(s); }else{ s->attempts_left--; #ifdef WITH_IMS_PM subs_cnt++; #endif } }else if (s->attempts_left==0) { /* we failed to many times, drop the subscription */ LOG(L_ERR,"ERR:"M_NAME":subscription_timer: Error on SUBSCRIBE for %d times... aborting\n",pcscf_subscribe_retries); del_r_subscription_nolock(s); }else{ /* we are subscribed already */ /* if expired, drop it */ if (s->expires<time_now) del_r_subscription_nolock(s); #ifdef WITH_IMS_PM else subs_cnt++; #endif /* if not expired, check for renewal */ // Commented as the S-CSCF should adjust the subscription time accordingly // if ((s->duration<1200 && s->expires-time_now<s->duration/2)|| // (s->duration>=1200 && s->expires-time_now<600)) // { // /* if we need a resubscribe, we mark it as such and try to subscribe again */ // s->attempts_left = pcscf_subscribe_retries; // ns = s; // } } s = ns; } subs_unlock(i); } print_subs(L_INFO); #ifdef WITH_IMS_PM IMS_PM_LOG01(RD_NbrSubs,subs_cnt); #endif }
/** * Debug print the contents of the entire registrar. * @param log_level - logging level */ void print_r(int log_level) { r_public *p; r_contact *c; r_subscriber *s; int i; if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */ r_act_time(); LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Registrar Contents begin --------\n"); for(i=0;i<r_hash_size;i++){ r_lock(i); p = registrar[i].head; while(p){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4d] P: <"ANSI_BLUE"%.*s"ANSI_GREEN"> R["ANSI_MAGENTA"%2d"ANSI_GREEN"] Early-IMS: <"ANSI_YELLOW"%.*s"ANSI_GREEN"> \n",i, p->aor.len,p->aor.s,p->reg_state,p->early_ims_ip.len,p->early_ims_ip.s); if (p->ccf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": CCF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> CCF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ccf1.len,p->ccf1.s,p->ccf2.len,p->ccf2.s); if (p->ecf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": ECF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> ECF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ecf1.len,p->ecf1.s,p->ecf2.len,p->ecf2.s); c = p->head; while(c){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": C: <"ANSI_RED"%.*s"ANSI_GREEN"> Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"]\n", c->uri.len,c->uri.s,c->expires-time_now); LOG(log_level,ANSI_GREEN"INF:"M_NAME": UP: {"ANSI_BLUE" iptv[%s], text[%s], data[%s], audio[%s], video[%s], control[%s], isfocus[%s], automata[%s], application[%s]\n mobility[%s]"ANSI_GREEN" }\n", ((c->user_pref->iptv == TRUE)?"yes":"no"), ((c->user_pref->text == TRUE)?"yes":"no"), ((c->user_pref->data == TRUE)?"yes":"no"), ((c->user_pref->audio == TRUE)?"yes":"no"), ((c->user_pref->video == TRUE)?"yes":"no"), ((c->user_pref->control == TRUE)?"yes":"no"), ((c->user_pref->isfocus == TRUE)?"yes":"no"), ((c->user_pref->automata == TRUE)?"yes":"no"), ((c->user_pref->application== TRUE)?"yes":"no"), ((c->user_pref->mobility.val_list[0] == MOBILE)?"mobile":"fixed") ) ; LOG(log_level,ANSI_GREEN"INF:"M_NAME": Path:"ANSI_YELLOW"%.*s"ANSI_GREEN"\n",c->path.len,c->path.s); LOG(log_level,ANSI_GREEN"INF:"M_NAME": UA: <%.*s>\n", c->ua.len,c->ua.s); c = c->next; } s = p->shead; while(s){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": S: Event["ANSI_BLUE"%d"ANSI_GREEN "] Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"] <"ANSI_CYAN"%.*s"ANSI_GREEN"> \n", s->event,s->expires-time_now,s->subscriber.len,s->subscriber.s); s = s->next; } p = p->next; } r_unlock(i); } LOG(log_level,"INF:"M_NAME":---------- Registrar Contents end ----------\n"); }
/** * Saves the IPSec information into the P-CSCF registrar for this contact. * @param req - REGISTER request * @param rpl - REGISTER respons * @param spi_uc - SPI for UE client * @param spi_us - SPI for UE server * @param spi_pc - SPI for PCSCF client * @param spi_ps - SPI for PCSCF server * @param port_uc - port for UE client * @param port_us - port for UE server * @param ealg_setkey - Chypher algorithm * @param ck_esp - Cypher Key * @param alg_setkey - Integrity algorithm * @param ik_esp - Integrity Key */ void save_contact_ipsec(struct sip_msg *req,struct sip_msg *rpl, int spi_uc,int spi_us,int spi_pc,int spi_ps,int port_uc,int port_us, str ealg_setkey,str ck_esp,str alg_setkey,str ik_esp) { contact_t* c=0; contact_body_t* b=0; r_contact *rc; enum Reg_States reg_state=REG_PENDING; int expires,pending_expires=60; struct sip_uri puri; r_ipsec *ipsec; if (parse_headers(rpl, HDR_EOH_F, 0) <0) { LOG(L_ERR,"ERR:"M_NAME":save_contact_ipsec: error parsing headers\n"); return ; } b = cscf_parse_contacts(req); if (!b||!b->contacts) { LOG(L_ERR,"ERR:"M_NAME":save_contact_ipsec: No contacts found\n"); return; } if (b) c = b->contacts; r_act_time(); while(c){ LOG(L_DBG,"DBG:"M_NAME":save_contact_ipsec: <%.*s>\n",c->uri.len,c->uri.s); expires = time_now+pending_expires; if (parse_uri(c->uri.s,c->uri.len,&puri)<0){ LOG(L_DBG,"DBG:"M_NAME":save_contact_ipsec: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s); goto next; } if (puri.port_no==0) puri.port_no=5060; LOG(L_DBG,"DBG:"M_NAME":save_contact_ipsec: %d %.*s : %d\n", puri.proto, puri.host.len,puri.host.s,puri.port_no); ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us, ealg_setkey,ck_esp,alg_setkey,ik_esp); rc = update_r_contact_sec(puri.host,ipsec->port_us,puri.proto, &(c->uri),®_state,&expires, ipsec); next: c = c->next; } //print_r(L_CRIT); }
/** * Generate notifications and put them in the notification queue to be sent * \note Must be called with a lock on the r_public pv * @param pv - r_public to generate for * @param c - r_contact to generate for or NULL if for all * @param ps - r_subscriber to generated for or NULL if for all * @param event_type - event type * @param send_now - whether to send immediately or delay * @returns 1 on success, 0 on failure */ int S_event_reg(void *pv,void *c,void *ps,int event_type,int send_now) { r_public *p=(r_public*)pv; r_subscriber *s=(r_subscriber*)ps; str content={0,0}; long subsExpires=-1; r_act_time(); switch (event_type){ case IMS_REGISTRAR_NONE: if (send_now) notification_timer(0,0); return 0; break; case IMS_REGISTRAR_SUBSCRIBE: content = r_get_reginfo_full(p,event_type,&subsExpires); r_create_notifications(p,0,s,content,subsExpires); if (content.s) pkg_free(content.s); if (send_now) notification_timer(0,0); return 1; break; case IMS_REGISTRAR_UNSUBSCRIBE: subsExpires=0; r_create_notifications(p,0,s,content,subsExpires); if (content.s) pkg_free(content.s); if (send_now) notification_timer(0,0); return 1; break; case IMS_REGISTRAR_CONTACT_REGISTERED: case IMS_REGISTRAR_CONTACT_CREATED: case IMS_REGISTRAR_CONTACT_REFRESHED: case IMS_REGISTRAR_CONTACT_SHORTENED: case IMS_REGISTRAR_CONTACT_EXPIRED: case IMS_REGISTRAR_CONTACT_DEACTIVATED: case IMS_REGISTRAR_CONTACT_PROBATION: case IMS_REGISTRAR_CONTACT_UNREGISTERED: case IMS_REGISTRAR_CONTACT_REJECTED: content = r_get_reginfo_partial(p,c,event_type,&subsExpires); r_create_notifications(p,c,s,content,subsExpires); if (content.s) pkg_free(content.s); if (send_now) notification_timer(0,0); return 1; break; default: LOG(L_ERR,"ERR:"M_NAME":S_event_reg: Unknown event %d\n",event_type); if (send_now) notification_timer(0,0); return 0; } }
/** * Searches for a r_public record and returns its expiration value. * @param aor - the address of record to look for * @returns - the expiration of the r_public if found or -999 if not found */ int get_r_public_expires(str aor) { int max_expires=-999; r_contact *c; r_public *p=get_r_public(aor); if (!p) return -999; r_act_time(); for(c=p->head;c;c=c->next) if (c->expires-time_now>max_expires){ max_expires = c->expires - time_now; } r_unlock(p->hash); return max_expires; }
void print_subs(int log_level) { r_subscription *s; int i; LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list begin ---------\n"); for(i=0;i<subscriptions_hash_size;i++){ subs_lock(i); s = subscriptions[i].head; r_act_time(); while(s){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4u]\tP: <"ANSI_BLUE"%.*s"ANSI_GREEN"> D:["ANSI_CYAN"%5d"ANSI_GREEN"] E:["ANSI_MAGENTA"%5d"ANSI_GREEN"] Att:[%2d]\n", s->hash,s->req_uri.len,s->req_uri.s,s->duration,(int)(s->expires-time_now),s->attempts_left); s = s->next; } subs_unlock(i); } LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Subscription list end -----------\n"); }
/** * Debug print the contents of the entire registrar. * @param log_level - logging level */ void print_r(int log_level) { r_public *p; r_contact *c; r_subscriber *s; int i; if (debug<log_level) return; /* to avoid useless calls when nothing will be printed */ r_act_time(); LOG(log_level,ANSI_GREEN"INF:"M_NAME":---------- Registrar Contents begin --------\n"); for(i=0;i<r_hash_size;i++){ r_lock(i); p = registrar[i].head; while(p){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4d] P: <"ANSI_BLUE"%.*s"ANSI_GREEN"> R["ANSI_MAGENTA"%2d"ANSI_GREEN"] Early-IMS: <"ANSI_YELLOW"%.*s"ANSI_GREEN"> \n",i, p->aor.len,p->aor.s,p->reg_state,p->early_ims_ip.len,p->early_ims_ip.s); if (p->ccf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": CCF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> CCF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ccf1.len,p->ccf1.s,p->ccf2.len,p->ccf2.s); if (p->ecf1.len) LOG(log_level,ANSI_GREEN"INF:"M_NAME": ECF1: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> ECF2: <"ANSI_MAGENTA"%.*s"ANSI_GREEN"> \n", p->ecf1.len,p->ecf1.s,p->ecf2.len,p->ecf2.s); c = p->head; while(c){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": C: <"ANSI_RED"%.*s"ANSI_GREEN"> Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"]\n", c->uri.len,c->uri.s,c->expires-time_now); LOG(log_level,ANSI_GREEN"INF:"M_NAME": Path:"ANSI_YELLOW"%.*s"ANSI_GREEN"\n",c->path.len,c->path.s); LOG(log_level,ANSI_GREEN"INF:"M_NAME": UA: <%.*s>\n", c->ua.len,c->ua.s); c = c->next; } s = p->shead; while(s){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": S: Event["ANSI_BLUE"%d"ANSI_GREEN "] Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"] <"ANSI_CYAN"%.*s"ANSI_GREEN"> \n", s->event,s->expires-time_now,s->subscriber.len,s->subscriber.s); s = s->next; } p = p->next; } r_unlock(i); } LOG(log_level,"INF:"M_NAME":---------- Registrar Contents end ----------\n"); }
/** * Process the REGISTER and verify Client-Security. * @param req - Register request * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_verify_security(struct sip_msg *req,char *str1, char *str2) { str sec_hdr; struct hdr_field *h; struct via_body *vb; r_contact *c; r_security *s; r_security_type sec_type; float sec_q; str ealg,alg,tmp; unsigned int spi_pc,spi_ps;; int port_pc,port_ps; vb = cscf_get_first_via(req,&h); LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ //first register LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Contact found ! \n"); return CSCF_RETURN_TRUE; } if (!r_valid_contact(c) || !c->security_temp){ LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No security temp !.\n"); r_unlock(c->hash); return CSCF_RETURN_TRUE; } sec_hdr = cscf_get_pref_security_header(req,s_security_verify, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Security-Verify header found.\n"); r_unlock(c->hash); return CSCF_RETURN_TRUE; } s = c->security_temp; switch (s->type) { case SEC_NONE: break; case SEC_TLS: if (sec_type != SEC_TLS || req->rcv.dst_port != pcscf_tls_port) goto error; break; case SEC_IPSEC: if (sec_type != SEC_IPSEC || req->rcv.dst_port != pcscf_ipsec_port_s) { LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Not IPSEC tunnel!.\n"); r_unlock(c->hash); goto error; } get_param(sec_hdr,s_ealg,ealg); get_param(sec_hdr,s_alg,alg); /* and for spis */ get_param(sec_hdr,s_spi_c,tmp); strtoint(tmp,spi_pc); get_param(sec_hdr,s_spi_s,tmp); strtoint(tmp,spi_ps); /* and for ports */ get_param(sec_hdr,s_port_c,tmp); strtoint(tmp,port_pc); get_param(sec_hdr,s_port_s,tmp); strtoint(tmp,port_ps); if ((s->data.ipsec->r_ealg.len != ealg.len || strncasecmp(s->data.ipsec->r_ealg.s, ealg.s, ealg.len)) || (s->data.ipsec->r_alg.len != alg.len || strncasecmp(s->data.ipsec->r_alg.s, alg.s, alg.len)) || (s->data.ipsec->spi_pc != spi_pc) || (s->data.ipsec->spi_ps != spi_ps) || (pcscf_ipsec_port_c != port_pc) || (pcscf_ipsec_port_s != port_ps)) { LOG(L_INFO,"DBG:"M_NAME":P_verify_security: No valid Security-Verify header!.\n"); r_unlock(c->hash); goto error; } break; } r_unlock(c->hash); return CSCF_RETURN_TRUE; error: return CSCF_RETURN_FALSE; }
/** * Debug print the contents of the entire registrar. */ void print_r(int log_level) { r_public *p; r_contact *c; int i,j; #ifdef SER_MOD_INTERFACE if (!is_printable(log_level)) #else if (debug<log_level) #endif return; /* to avoid useless calls when nothing will be printed */ r_act_time(); LOG(log_level,"INF:"M_NAME":---------- Registrar Contents begin --------\n"); if (!registrar) return; for(i=0;i<r_hash_size;i++){ r_lock(i); c = registrar[i].head; while(c){ LOG(log_level,ANSI_GREEN"INF:"M_NAME":[%4d] C: <"ANSI_RED"%d://%.*s:%d"ANSI_GREEN"> Exp:["ANSI_MAGENTA"%4ld"ANSI_GREEN"] R:["ANSI_MAGENTA"%2d"ANSI_GREEN"] SOS:["ANSI_MAGENTA"%c"ANSI_GREEN"] <%.*s>\n",i, c->transport,c->host.len,c->host.s,c->port, c->expires-time_now,c->reg_state, (c->sos_flag & EMERG_REG)?'X':' ', c->uri.len,c->uri.s); for(j=0;j<c->service_route_cnt;j++) LOG(log_level,ANSI_GREEN"INF:"M_NAME": SR: <"ANSI_YELLOW"%.*s"ANSI_GREEN">\n",c->service_route[j].len,c->service_route[j].s); if(c->pinhole) { if (c->pinhole->nat_addr.len>=4) LOG(log_level,ANSI_GREEN"INF:"M_NAME": NAT:<"ANSI_CYAN"%d://%d.%d.%d.%d:%d"ANSI_GREEN">\n", c->pinhole->proto, c->pinhole->nat_addr.u.addr[0], c->pinhole->nat_addr.u.addr[1], c->pinhole->nat_addr.u.addr[2], c->pinhole->nat_addr.u.addr[3], (unsigned short)c->pinhole->nat_port); } if (c->security){ switch(c->security->type){ case SEC_NONE: break; case SEC_TLS: if (c->security->data.tls) LOG(log_level,ANSI_GREEN"INF:"M_NAME": TLS: %.*s tls://%.*s:%d\n", c->security->sec_header.len,c->security->sec_header.s, c->host.len,c->host.s,c->security->data.tls->port_tls); break; case SEC_IPSEC: if (c->security->data.ipsec) LOG(log_level,ANSI_GREEN"INF:"M_NAME": IPSec: UAS: %d:%d->%d UAC: %d:%d<-%d E[%.*s] I[%.*s]\n", c->security->data.ipsec->spi_uc,c->security->data.ipsec->port_uc,c->security->data.ipsec->spi_ps, c->security->data.ipsec->spi_us,c->security->data.ipsec->port_us,c->security->data.ipsec->spi_pc, c->security->data.ipsec->ealg.len,c->security->data.ipsec->ealg.s,c->security->data.ipsec->alg.len,c->security->data.ipsec->alg.s); } } if (c->security_temp){ switch(c->security_temp->type){ case SEC_NONE: break; case SEC_TLS: if (c->security_temp->data.tls) LOG(log_level,ANSI_GREEN"INF:"M_NAME": TLS: %.*s tls://%.*s:%d\n", c->security_temp->sec_header.len,c->security_temp->sec_header.s, c->host.len,c->host.s,c->security_temp->data.tls->port_tls); break; case SEC_IPSEC: if (c->security_temp->data.ipsec) LOG(log_level,ANSI_GREEN"INF:"M_NAME": Temp.IPSec: UAS: %d:%d->%d UAC: %d:%d<-%d E[%.*s] I[%.*s]\n", c->security_temp->data.ipsec->spi_uc,c->security_temp->data.ipsec->port_uc,c->security_temp->data.ipsec->spi_ps, c->security_temp->data.ipsec->spi_us,c->security_temp->data.ipsec->port_us,c->security_temp->data.ipsec->spi_pc, c->security_temp->data.ipsec->ealg.len,c->security_temp->data.ipsec->ealg.s,c->security_temp->data.ipsec->alg.len,c->security_temp->data.ipsec->alg.s); } } p = c->head; while(p){ LOG(log_level,ANSI_GREEN"INF:"M_NAME": P: D[%c] <"ANSI_BLUE"%.*s"ANSI_GREEN"> \n", (p->is_default?'X':' '),p->aor.len,p->aor.s); p = p->next; } c = c->next; } r_unlock(i); } LOG(log_level,"INF:"M_NAME":---------- Registrar Contents end ----------\n"); }
/** * Process the 200 response for REGISTER and creates the first Security-Associations. * The rest of the SA are not set. * could come over that one. * @param rpl - the 200 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_IPSec_200(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; struct hdr_field *hdr; str sec_cli; struct hdr_field *h; struct via_body *vb; r_contact *c; r_ipsec *i; int expires; char out_rpl[256],out_req[256],inc_rpl[256]; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: No transactional request found.\n"); goto error; } /* just to jump out if no IPSec is employed - the info is already saved */ sec_cli = cscf_get_security_client(req,&hdr); if (!sec_cli.len){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: No Security-Client header found.\n"); goto error; } /* find the expires (reg or dereg?) */ expires = cscf_get_max_expires(req); /* get the IPSec info from the registrar */ vb = cscf_get_first_via(req,&h); // if (!h||!h->parsed){ // LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Error extracting sender's id.\n"); // goto error; // } // vb = (struct via_body*) h->parsed; LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_200: Contact not found\n"); goto error; } if (!r_valid_contact(c)||!c->ipsec){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_200: Contact expired or no IPSec info\n"); r_unlock(c->hash); goto error; } i = c->ipsec; /* P_Out_Rpl */ sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Rpl, c->host.len,c->host.s, i->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, i->spi_uc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Req */ sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Req, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_us, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Inc_Rpl */ sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Rpl, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_pc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); if (expires<=0) { /* Deregister */ c->reg_state = DEREGISTERED; r_act_time(); c->expires = time_now + 60; } r_unlock(c->hash); //print_r(L_CRIT); /* run the IPSec scripts */ /* Registration */ execute_cmd(out_rpl); execute_cmd(out_req); execute_cmd(inc_rpl); return 1; error: return 0; }
/** * Saves the Contact Security information into the P-CSCF registrar for this contact. * @param req - REGISTER request * @param auth - WWW-Authenticate header * @param sec_hdr - Security header * @param type - Security Type * @param q - Preference Value */ r_contact* save_contact_security(struct sip_msg *req, str auth, str sec_hdr,r_security_type type,float q) { contact_t* c=0; contact_body_t* b=0; r_contact *rc; enum Reg_States reg_state=REG_PENDING; int expires,pending_expires=60; struct sip_uri puri; r_security *s=0; b = cscf_parse_contacts(req); if (!b||!b->contacts) { LOG(L_ERR,"ERR:"M_NAME":save_contact_security: No contacts found\n"); goto error; } if (b) c = b->contacts; r_act_time(); /* the Security works for just 1 contact/registration! */ if(c){ LOG(L_DBG,"DBG:"M_NAME":save_contact_security: <%.*s>\n",c->uri.len,c->uri.s); expires = time_now+pending_expires; if (parse_uri(c->uri.s,c->uri.len,&puri)<0){ LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s); goto error; } if (puri.port_no==0) puri.port_no=5060; LOG(L_DBG,"DBG:"M_NAME":save_contact_security: %d %.*s : %d\n", puri.proto, puri.host.len,puri.host.s,puri.port_no); if (type == SEC_TLS) puri.proto = PROTO_TLS; /* create the r_security structure */ s = new_r_security(sec_hdr,type,q); if (!s) goto error; switch(type) { case SEC_NONE: break; case SEC_TLS: // r_tls creation happens on 200 break; case SEC_IPSEC: { /* then parse the parameters */ r_ipsec *ipsec; str ck,ik,ealg,alg,tmp; str alg_setkey,ealg_setkey; unsigned int spi_uc,spi_us; unsigned int spi_pc,spi_ps; int port_uc,port_us; char ck_c[64],ik_c[64]; str ck_esp={ck_c,0},ik_esp={ik_c,0}; get_qparam(auth,s_ck,ck); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: CK: <%.*s>\n", ck.len,ck.s); get_qparam(auth,s_ik,ik); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: IK: <%.*s>\n", ik.len,ik.s); get_param(sec_hdr,s_ealg,ealg); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Enc Algorithm: <%.*s>\n", ealg.len,ealg.s); get_param(sec_hdr,s_alg,alg); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Int Algorithm: <%.*s>\n", alg.len,alg.s); /* and for spis */ get_param(sec_hdr,s_spi_c,tmp); strtoint(tmp,spi_uc); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-C: %d\n", spi_uc); get_param(sec_hdr,s_spi_s,tmp); strtoint(tmp,spi_us); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-S: %d\n", spi_us); /* and for ports */ get_param(sec_hdr,s_port_c,tmp); strtoint(tmp,port_uc); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-C: %d\n", port_uc); get_param(sec_hdr,s_port_s,tmp); strtoint(tmp,port_us); LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-S: %d\n", port_us); ck_esp.s[ck_esp.len++]='0'; ck_esp.s[ck_esp.len++]='x'; if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) { memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32; memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16; ealg_setkey = s_des_out; } else if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) { memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len; ealg_setkey = s_aes_out; }else { memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len; ealg_setkey = s_null_out; ealg = s_null_out; } ik_esp.s[ik_esp.len++]='0'; ik_esp.s[ik_esp.len++]='x'; if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) { memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len; alg_setkey = s_md5_out; } else if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) { memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len; memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8; alg_setkey = s_sha_out; }else{ LOG(L_ERR,"ERR:"M_NAME":save_contact_security: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s); goto error; } spi_pc=get_next_spi(); spi_ps=get_next_spi(); ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us, ealg_setkey,ealg, ck_esp,alg_setkey,alg, ik_esp); if (!ipsec) goto error; s->data.ipsec = ipsec; } break; } } rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto, &(c->uri),®_state,&expires,s); return rc; error: if (s) free_r_security(s); return 0; }
/** * Process the 200 response for REGISTER and creates the first Security-Associations. * The rest of the SA are not set. * could come over that one. * @param rpl - the 200 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_security_200(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; str sec_hdr; r_security_type sec_type; float sec_q; struct hdr_field *h; struct via_body *vb; r_contact *c; r_ipsec *i; int expires; unsigned long s_hash; char out_rpl[256],out_req[256],inc_rpl[256]; if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: No transactional request found.\n"); goto error; } sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_security_200: No Security-Verify header found.\n"); goto error; } /* find the expires (reg or dereg?) */ expires = cscf_get_max_expires(req); /* get the IPSec info from the registrar */ vb = cscf_get_first_via(req,&h); LOG(L_DBG,"DBG:"M_NAME":P_security_200: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port); c = get_r_contact(vb->host,vb->port,vb->proto); r_act_time(); if (!c){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: Contact not found\n"); goto error; } if (c->security_temp){ if (c->security && c->security->type == SEC_TLS && (c->security->data.tls && c->security->data.tls->port_tls==req->rcv.src_port&& c->security->data.tls->session_hash!=0 && c->security->data.tls->session_hash == tls_get_session_hash(req))){ /* don't replace security when doing an integrity protected REGISTER with * possible attack-garbage from security_temp */ P_security_drop(c,c->security_temp); free_r_security(c->security_temp); c->security_temp = 0; } else { if (c->security) { P_security_drop(c,c->security); free_r_security(c->security); } c->security = c->security_temp; c->security_temp = 0; } } switch(sec_type){ case SEC_NONE: break; case SEC_TLS: if (c->security && pcscf_use_tls) { r_tls *tls; int port_tls = req->rcv.src_port; s_hash = get_tls_session_hash(req); if (!s_hash){ LOG(L_ERR,"ERR:"M_NAME":P_security_200: Session Hash could not be obtained !\n"); r_unlock(c->hash); goto error; } tls = new_r_tls(port_tls, s_hash); if (!tls) goto error; c->security->data.tls = tls; } r_unlock(c->hash); break; case SEC_IPSEC: if (!r_valid_contact(c)||!c->security||!c->security->data.ipsec ){ LOG(L_DBG,"DBG:"M_NAME":P_security_200: Contact expired or no IPSec info\n"); r_unlock(c->hash); goto error; } i = c->security->data.ipsec; /* P_Out_Rpl */ sprintf(out_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Rpl, c->host.len,c->host.s, i->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, i->spi_uc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Req */ sprintf(out_req,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Out_Req, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_us, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); /* P_Out_Inc_Rpl */ sprintf(inc_rpl,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Rpl, c->host.len,c->host.s, i->port_us, pcscf_ipsec_host, pcscf_ipsec_port_c, i->spi_pc, i->ealg.len,i->ealg.s, i->ck.len,i->ck.s, i->alg.len,i->alg.s, i->ik.len,i->ik.s ); if (expires<=0) { /* Deregister */ c->reg_state = DEREGISTERED; r_act_time(); c->expires = time_now + 60; } r_unlock(c->hash); //print_r(L_CRIT); /* run the IPSec scripts */ /* Registration */ execute_cmd(out_rpl); execute_cmd(out_req); execute_cmd(inc_rpl); break; } return CSCF_RETURN_TRUE; ret_false: return CSCF_RETURN_FALSE; error: return CSCF_RETURN_ERROR; }
/** * Save this subscription. * @param msg - the SIP SUBSCRIBE message * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if allowed, #CSCF_RETURN_FALSE if not, #CSCF_RETURN_ERROR on error */ int S_subscribe(struct sip_msg *msg,char *str1,char *str2) { int ret=CSCF_RETURN_FALSE; struct sip_uri puri; str uri={0,0}; str event; int event_i=IMS_EVENT_NONE; int expires=0,expires_time=0; str subscriber; r_public *p=0; r_subscriber *s=0,*new_s=0; dlg_t *dialog=0; LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Saving SUBSCRIBE\n"); /* First check the parameters */ if (msg->first_line.type!=SIP_REQUEST) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a request\n"); goto error; } if (msg->first_line.u.request.method.len != 9 || memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a SUBSCRIBE\n"); goto error; } /* 1. Get the event */ event = cscf_get_event(msg); if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n", event.len,event.s); ret = CSCF_RETURN_FALSE; goto done; } if (event.len==0 && strncasecmp(event.s,"reg",3)==0) event_i = IMS_EVENT_REG; /* 2. Get the target of the SUBSCRIBE from RequestURI */ if (msg->new_uri.s) uri = msg->new_uri; else uri = msg->first_line.u.request.uri; if (parse_uri(uri.s, uri.len, &puri) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error parsing uri <%.*s>\n", uri.len,uri.s); goto error; } uri.len = lookup_sip.len+puri.user.len+1+puri.host.len; uri.s = pkg_malloc(uri.len); if (!uri.s){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error allocating %d bytes\n",uri.len); goto error; } uri.len=0; memcpy(uri.s,lookup_sip.s,lookup_sip.len); uri.len+=lookup_sip.len; memcpy(uri.s+uri.len,puri.user.s,puri.user.len); uri.len+=puri.user.len; uri.s[uri.len++]='@'; memcpy(uri.s+uri.len,puri.host.s,puri.host.len); uri.len+=puri.host.len; /* 3. Get the Subscriber's Identity */ subscriber = cscf_get_contact(msg); if (!subscriber.len){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Contact empty.\n"); ret = CSCF_RETURN_FALSE; goto done; } LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Contact <%.*s>.\n", subscriber.len,subscriber.s); p = get_r_public(uri); /* Registration is possible even if the user is not registered... so just create one */ if (!p){ p = add_r_public(uri,0,0); } if (!p){ LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Identity not found and error on creation <%.*s>\n", uri.len,uri.s); ret = CSCF_RETURN_FALSE; goto done; } expires = cscf_get_expires_hdr(msg,0); if (expires == -1) expires = subscription_default_expires; if (expires > 0) { if (expires < subscription_min_expires) expires = subscription_min_expires; if (expires > subscription_max_expires) expires = subscription_max_expires; r_act_time(); expires_time = expires + time_now; /* get the old subscriber - if any */ s = get_r_subscriber(p,subscriber,event_i); if (!s){ /* create a new dialog */ if (tmb.new_dlg_uas(msg, 200, &dialog) < 0) { LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error while creating dialog state\n"); ret = CSCF_RETURN_FALSE; goto error; } }else dialog = s->dialog; /* update the subscriber */ if ((new_s=update_r_subscriber(p,subscriber,event_i,&expires_time,dialog))!=0){ //if (!s) /* Only on first subscription, not on refreshes, send a notify */ S_event_reg(p,0,new_s,IMS_REGISTRAR_SUBSCRIBE,0); ret = CSCF_RETURN_TRUE; } else ret = CSCF_RETURN_FALSE; }else{ /* Unsubscribe */ /* get the old subscriber - if any */ r_act_time(); s = get_r_subscriber(p,subscriber,event_i); if (s) { s->expires = time_now; S_event_reg(p,0,s,IMS_REGISTRAR_UNSUBSCRIBE,1); del_r_subscriber(p,s); } ret = CSCF_RETURN_TRUE; } done: r_unlock(p->hash); if (expires ==0 )S_SUBSCRIBE_reply(msg,200,MSG_REG_UNSUBSCRIBE_OK,&expires,&uri); else S_SUBSCRIBE_reply(msg,200,MSG_REG_SUBSCRIBE_OK,&expires,&uri); if (uri.s) pkg_free(uri.s); return ret; error: if (p) r_unlock(p->hash); if (uri.s) pkg_free(uri.s); ret=CSCF_RETURN_FALSE; return ret; }