/** * Looks for the UE Via in First Via header if its a request * or in the last if its a response and returns its body * @param msg - the SIP message * @returns the via of the UE */ struct via_body* cscf_get_ue_via(struct sip_msg *msg) { struct via_body *vb=0; if (msg->first_line.type==SIP_REQUEST) vb = cscf_get_first_via(msg,0); else vb = cscf_get_last_via(msg); if (!vb) return 0; if (vb->port == 0) vb->port=5060; return vb; }
/** * 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; }
/** * 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; }
/** * 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; }