/** * Returns the expires value from the message. * First it searches into the Expires header and if not found it also looks * into the expires parameter in the contact header * @param msg - the SIP message * @param is_shm - msg from shared memory * @returns the value of the expire or the default 3600 if none found */ int cscf_get_max_expires(struct sip_msg *msg, int is_shm) { unsigned int exp; int max_expires = -1; struct hdr_field *h; contact_t *c; /*first search in Expires header */ max_expires = cscf_get_expires_hdr(msg, is_shm); cscf_parse_contacts(msg); for(h=msg->contact;h;h=h->next){ if (h->type==HDR_CONTACT_T && h->parsed) { for(c=((contact_body_t *) h->parsed)->contacts;c;c=c->next){ if(c->expires){ if (!str2int(&(c->expires->body), (unsigned int*)&exp) && (int)exp>max_expires) max_expires = exp; } } } } if(is_shm){ for(h=msg->contact;h;h=h->next){ if (h->type==HDR_CONTACT_T && h->parsed) { free_contact((contact_body_t**)&(h->parsed)); h->parsed = 0; } } } return max_expires; }
/** * 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); }
/** * Subscribe to the reg event to the S-CSCF. * @param rpl - 200 OK response to REGISTER containing contacts and Service-Route header * @param str1 - not used * @param str2 - not used * @returns #CSCF_RETURN_TRUE if subscribed, #CSCF_RETURN_FALSE if not or #CSCF_RETURN_ERROR on error */ int P_subscribe(struct sip_msg *rpl, char* str1, char* str2) { int expires_hdr=0,r,max_expires; str public_id={0,0}; contact_t* c=0; contact_body_t* b=0; cscf_get_first_p_associated_uri(rpl,&public_id); expires_hdr = cscf_get_expires_hdr(rpl); if (parse_headers(rpl, HDR_EOH_F, 0) <0) { LOG(L_ERR,"ERR:"M_NAME":P_subscribe: error parsing headers\n"); return CSCF_RETURN_ERROR; } b = cscf_parse_contacts(rpl); if (!b||!b->contacts) { LOG(L_DBG,"DBG:"M_NAME":P_subscribe: No contacts found\n"); return CSCF_RETURN_FALSE; } if (b) c = b->contacts; max_expires = expires_hdr; while(c){ r = expires_hdr; if (str2int(&(c->expires->body), (unsigned int*)&r) < 0) { r = 0; } if (r>max_expires) max_expires = r; c = c->next; } if (max_expires<=0){ LOG(L_INFO,"DBG:"M_NAME":P_subscribe: skipped because de-register\n"); return CSCF_RETURN_FALSE; } if (public_id.s){ // if (max_expires==0) // r_subscribe(public_id,0); // else r_subscribe(public_id,max_expires+30); return CSCF_RETURN_TRUE; }else{ return CSCF_RETURN_FALSE; } }
/* * sends an AAR for every registered contact * returns CSCF_RETURN_TRUE on ok and CSCF_RETURN_FALSE on error * TODO:on error: if any AAR was sent, STR will be sent by the authstatemachine */ int P_AAR_register(struct sip_msg *req, struct sip_msg * rpl) { AAAMessage* resp; unsigned int result = AAA_SUCCESS; contact_body_t * aor_list; contact_t * crt_aor = NULL; str pcc_session_id = {0,0}; if (parse_headers(rpl, HDR_EOH_F, 0) <0) { LOG(L_ERR,"ERR:"M_NAME":P_Rx_register: error parsing headers\n"); return CSCF_RETURN_FALSE; } aor_list = cscf_parse_contacts(req); if (!aor_list || (!aor_list->contacts && !aor_list->star)) { LOG(L_ERR,"ERR:"M_NAME":P_Rx_register: no contacts found in the Contact header\n"); return CSCF_RETURN_FALSE; } for(crt_aor = aor_list->contacts; crt_aor!=NULL; crt_aor= crt_aor->next) { resp = PCC_AAR(req, rpl, "reg", crt_aor, &pcc_session_id, 0); if(!resp) goto error; if(PCC_AAA(resp, &result, pcc_session_id) > 0) { LOG(L_INFO,"INFO:"M_NAME":P_Rx_register:recieved an AAA with result code %u\n",result); if(result<2000 || result >= 3000) { cdpb.AAAFreeMessage(&resp); goto error; } } cdpb.AAAFreeMessage(&resp); } return CSCF_RETURN_TRUE; error: LOG(L_INFO,"INFO:"M_NAME":P_Rx_register:recieved an AAA with error code or null AAA\n"); return CSCF_RETURN_FALSE; }
/** * Returns the expires value from the message. * First it searches into the Expires header and if not found it also looks * into the expires parameter in the contact header * @param msg - the SIP message * @returns the value of the expire or the default 3600 if none found */ int cscf_get_max_expires(struct sip_msg *msg) { unsigned int exp; int max_expires = -1; struct hdr_field *h; contact_t *c; /*first search in Expires header */ max_expires = cscf_get_expires_hdr(msg); cscf_parse_contacts(msg); for(h=msg->contact;h;h=h->next){ if (h->type==HDR_CONTACT_T && h->parsed) { for(c=((contact_body_t *) h->parsed)->contacts;c;c=c->next){ if(c->expires){ if (!str2int(&(c->expires->body), (unsigned int*)&exp) && (int)exp>max_expires) max_expires = exp; } } } } LOG(L_DBG,"DBG:"M_NAME":cscf_get_max_expires: <%d> \n",max_expires); return max_expires; }
/** * P_STR() will be called, if PCSCF receives BYE, CANCEL, 3xx, 4xx, 5xx or 6xx. * It terminates the created auth session with the PDF. * */ int P_STR(struct sip_msg* msg, char* str1, char* str2) { // get session id from sip msg // Gq_STR(session_id) terminate the session AAAMessage* sta=0; contact_t * crt_cnt = NULL; contact_body_t * cnt_list; if (!pcscf_use_pcc) return CSCF_RETURN_TRUE; LOG(L_INFO, ANSI_WHITE"INF:"M_NAME":P_STR:\n"); int is_register=(str1 && (str1[0]=='r' || str1[0]=='R')); if(is_register) { if (parse_headers(msg, HDR_EOH_F, 0) <0) { LOG(L_ERR,"ERR:"M_NAME":P_STR: error parsing headers\n"); return CSCF_RETURN_FALSE; } cnt_list = cscf_parse_contacts(msg); if (!cnt_list || (!cnt_list->contacts && !cnt_list->star)) { LOG(L_ERR,"ERR:"M_NAME":P_STR: no contacts found in the Contact header\n"); return CSCF_RETURN_FALSE; } for(crt_cnt = cnt_list->contacts; crt_cnt!=NULL; crt_cnt= crt_cnt->next) { sta = PCC_STR(msg,str1, crt_cnt); // if you really want the STA just declare a ResponseHandler for it because its never going // to arrive here.. or never again if (sta) cdpb.AAAFreeMessage(&sta); } } else { sta = PCC_STR(msg,str1, NULL); } return CSCF_RETURN_TRUE; }
pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d, enum pcontact_reg_states reg_state, char service_routes[][MAXROUTESIZE], int num_service_routes) { ppublic_t * p; contact_body_t *b = 0; contact_t *ct; pcontact_info_t search_ci; str received_host = {0, 0}; char srcip[50]; struct via_body *vb; unsigned short port, proto; str host; sip_uri_t contact_uri; int mustRetryViaSearch = 0; int mustRetryReceivedSearch = 0; LM_DBG("number of service routes to look for is %d\n", num_service_routes); b = cscf_parse_contacts(_m); if (_m->first_line.type == SIP_REPLY && _m->contact && _m->contact->parsed && b->contacts) { mustRetryViaSearch = 1; mustRetryReceivedSearch = 1; LM_DBG("This is a reply - to look for contact we favour the contact header above the via (b2bua)... if no contact we will use last via\n"); ct = b->contacts; host = ct->uri; if (parse_uri(ct->uri.s, ct->uri.len, &contact_uri) != 0) { LM_WARN("Failed to parse contact [%.*s]\n", ct->uri.len, ct->uri.s); return NULL; } host = contact_uri.host; port = contact_uri.port_no ? contact_uri.port_no : 5060; proto = contact_uri.proto; if (proto == 0) { LM_DBG("Contact protocol not specified - using received\n"); proto = _m->rcv.proto; } } else { if (_m->first_line.type == SIP_REPLY) LM_DBG("This is a reply but we are forced to use the via header\n"); else LM_DBG("This is a request - using first via to find contact\n"); vb = cscf_get_ue_via(_m); host = vb->host; port = vb->port ? vb->port : 5060; proto = vb->proto; } LM_DBG("searching for contact with host:port:proto contact [%d://%.*s:%d]\n", proto, host.len, host.s, port); received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof (srcip)); received_host.s = srcip; // if (_m->id != current_msg_id) { current_msg_id = _m->id; c = NULL; //search_ci.reg_state = PCONTACT_REGISTERED; //we can do this because this function is always called expecting a REGISTERED contact memset(&search_ci, 0, sizeof(struct pcontact_info)); search_ci.reg_state = reg_state; search_ci.received_host.s = received_host.s; search_ci.received_host.len = received_host.len; search_ci.received_port = _m->rcv.src_port; search_ci.received_proto = _m->rcv.proto; search_ci.searchflag = SEARCH_RECEIVED; search_ci.num_service_routes = 0; if (is_registered_fallback2ip == 1) { search_ci.searchflag = SEARCH_NORMAL; } search_ci.via_host = host; search_ci.via_port = port; search_ci.via_prot = proto; search_ci.aor.s = 0; search_ci.aor.len = 0; int size = num_service_routes==0?1:num_service_routes; str s_service_routes[size]; int i; for (i=0;i<num_service_routes;i++) { s_service_routes[i].s = service_routes[i]; s_service_routes[i].len = strlen(service_routes[i]); LM_DBG("Setting service routes str for pos %d to %.*s", i, s_service_routes[i].len, s_service_routes[i].s); } if (num_service_routes > 0) { LM_DBG("asked to search for specific service routes...\n"); search_ci.service_routes = s_service_routes; search_ci.num_service_routes = num_service_routes; search_ci.extra_search_criteria = SEARCH_SERVICE_ROUTES; } // b = cscf_parse_contacts(_m); tryagain: if (b && b->contacts) { for (ct = b->contacts; ct; ct = ct->next) { search_ci.aor = ct->uri; if (ul.get_pcontact(_d, &search_ci, &c) == 0) { if (checkcontact(_m, c) != 0) { c = NULL; } else { break; } } } } else { LM_WARN("No contact-header found...\n"); } if ((c == NULL) && (is_registered_fallback2ip == 1)) { LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n"); // received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); // received_host.s = srcip; search_ci.searchflag = SEARCH_RECEIVED; if (ul.get_pcontact(_d, &search_ci, &c) == 1) { LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); } else { if (checkcontact(_m, c) != 0) { c = NULL; } } } if ((c == NULL) && (is_registered_fallback2ip == 2)) { LM_INFO("Contact not found based on IP/Port/Proto, trying Contact-header\n"); search_ci.searchflag = SEARCH_NORMAL; if (ul.get_pcontact(_d, &search_ci, &c) == 1) { } else { if (checkcontact(_m, c) != 0) { c = NULL; } } } asserted_identity = NULL; registration_contact = NULL; if (c) { LM_DBG("Trying to set asserted identity field"); registration_contact = &c->contact_user; p = c->head; while (p) { LM_DBG("Checking through contact users"); if (p->is_default == 1) { LM_DBG("Found default contact user so setting asserted identity"); asserted_identity = &p->public_identity; } p = p->next; } } if (asserted_identity != NULL && asserted_identity->len > 0) { LM_DBG("Have set the asserted_identity param to [%.*s]\n", asserted_identity->len, asserted_identity->s); } else { LM_DBG("Asserted identity not set"); } // LM_DBG("pcontact flag is [%d]\n", c->flags); // if (c && (c->flags & (1<<FLAG_READFROMDB)) != 0) { // LM_DBG("we have a contact that was read fresh from the DB....\n"); // } if (!c && mustRetryViaSearch) { LM_DBG("This is a reply so we will search using the last via once more...\n"); vb = cscf_get_ue_via(_m); search_ci.via_host = vb->host; search_ci.via_port = vb->port ? vb->port : 5060; search_ci.via_prot = vb->proto; mustRetryViaSearch = 0; goto tryagain; } if (!c && mustRetryReceivedSearch) { LM_DBG("This is a reply and we still don't have a match - will try src ip/port of message\n"); search_ci.via_host = received_host; search_ci.via_port = _m->rcv.src_port; search_ci.via_prot = _m->rcv.proto; mustRetryReceivedSearch = 0; goto tryagain; } return c; }
/** * Perform User Authorization Request. * creates and send the user authorization query * @param msg - the SIP message * @param str1 - the realm * @param str2 - if to do capabilities * @returns true if OK, false if not */ int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2) { str private_identity, public_identity, visited_network_id; int authorization_type = AVP_IMS_UAR_REGISTRATION; int expires = 3600; struct hdr_field *hdr; str realm; contact_t *c; int sos_reg = 0; contact_body_t *b = 0; str call_id; saved_uar_transaction_t* saved_t; tm_cell_t *t = 0; int intvalue_param; cfg_action_t* cfg_action; uar_param_t* ap = (uar_param_t*) str1; if (fixup_get_ivalue(msg, ap->ivalue, &intvalue_param) != 0) { LM_ERR("no int value param passed\n"); return CSCF_RETURN_ERROR; } cfg_action = ap->paction->next; realm = cscf_get_realm_from_ruri(msg); //check if we received what we should, we do this even though it should be done in cfg file - double checking! if (msg->first_line.type != SIP_REQUEST) { LM_ERR("ERR:I_UAR: The message is not a request\n"); return CSCF_RETURN_ERROR; } if (msg->first_line.u.request.method.len != 8 || memcmp(msg->first_line.u.request.method.s, "REGISTER", 8) != 0) { LM_ERR("ERR:I_UAR: The method is not a REGISTER\n"); return CSCF_RETURN_ERROR; } private_identity = cscf_get_private_identity(msg, realm); if (!private_identity.len) { LM_ERR("ERR:I_UAR: Private Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_PRIVATE); return CSCF_RETURN_BREAK; } public_identity = cscf_get_public_identity(msg); if (!public_identity.len) { LM_ERR("ERR:I_UAR: Public Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC); return CSCF_RETURN_BREAK; } b = cscf_parse_contacts(msg); if (!b || (!b->contacts && !b->star)) { LM_DBG("DBG:I_UAR: No contacts found\n"); return CSCF_RETURN_ERROR; } for (c = b->contacts; c; c = c->next) { sos_reg = cscf_get_sos_uri_param(c->uri); if (sos_reg == -1) { //error case LM_ERR("ERR:I_UAR: MSG_400_MALFORMED_CONTACT, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_MALFORMED_CONTACT); return CSCF_RETURN_BREAK; } else if (sos_reg == -2) { LM_ERR("ERR:I_UAR: MSG_500_SERVER_ERROR_OUT_OF_MEMORY, responding with 500\n"); cscf_reply_transactional(msg, 500, MSG_500_SERVER_ERROR_OUT_OF_MEMORY); return CSCF_RETURN_BREAK; } } visited_network_id = cscf_get_visited_network_id(msg, &hdr); if (!visited_network_id.len) { LM_ERR("ERR:I_UAR: Visited Network Identity not found, responding with 400\n"); cscf_reply_transactional(msg, 400, MSG_400_NO_VISITED); return CSCF_RETURN_BREAK; } if (atoi(str1)) authorization_type = AVP_IMS_UAR_REGISTRATION_AND_CAPABILITIES; else { expires = cscf_get_max_expires(msg, 0); if (expires == 0) authorization_type = AVP_IMS_UAR_DE_REGISTRATION; } LM_DBG("SENDING UAR: PI: [%.*s], PU: [%.*s], VNID: [%.*s]\n", private_identity.len, private_identity.s, public_identity.len, public_identity.s, visited_network_id.len, visited_network_id.s); //before we send lets suspend the transaction t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for UAR async\n"); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } } saved_t = shm_malloc(sizeof (saved_uar_transaction_t)); if (!saved_t) { LM_ERR("no more memory trying to save transaction state\n"); return CSCF_RETURN_ERROR; } memset(saved_t, 0, sizeof (saved_uar_transaction_t)); saved_t->act = cfg_action; call_id = cscf_get_call_id(msg, 0); saved_t->callid.s = (char*) shm_malloc(call_id.len + 1); if (!saved_t->callid.s) { LM_ERR("no more memory trying to save transaction state : callid\n"); shm_free(saved_t); return CSCF_RETURN_ERROR; } memset(saved_t->callid.s, 0, call_id.len + 1); memcpy(saved_t->callid.s, call_id.s, call_id.len); saved_t->callid.len = call_id.len; LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n"); create_uaa_return_code(CSCF_RETURN_ERROR); LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_uar_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } if (cxdx_send_uar(msg, private_identity, public_identity, visited_network_id, authorization_type, sos_reg, saved_t) != 0) { LM_ERR("ERR:I_UAR: Error sending UAR or UAR time-out\n"); tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel); free_saved_uar_transaction_data(saved_t); cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR); return CSCF_RETURN_BREAK; } //we use async replies therefore we send break and not true when successful return CSCF_RETURN_BREAK; }
/** * get PContact-Structure for message * (search only once per Request) */ pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) { ppublic_t * p; contact_body_t *b = 0; str received_host = {0, 0}; contact_t *ct; char srcip[50]; int security_server_port = -1; if (_m->id != current_msg_id) { current_msg_id = _m->id; c = NULL; b = cscf_parse_contacts(_m); if (b && b->contacts) { for (ct = b->contacts; ct; ct = ct->next) { if (ul.get_pcontact(_d, &ct->uri, &c) == 0) { if (c->security) { switch (c->security->type) { case SECURITY_IPSEC: security_server_port = c->security->data.ipsec->port_uc; break; case SECURITY_TLS: case SECURITY_NONE: break; } } else if (c->security_temp) { switch (c->security->type) { case SECURITY_IPSEC: security_server_port = c->security->data.ipsec->port_uc; break; case SECURITY_TLS: case SECURITY_NONE: break; } } if ((c->reg_state == PCONTACT_REGISTERED) && ((c->received_port == _m->rcv.src_port) || (security_server_port == _m->rcv.src_port)) && (c->received_proto == _m->rcv.proto)) { received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); received_host.s = srcip; LM_DBG("Received host len %d (search %d)\n", c->received_host.len, received_host.len); // Then check the length: if (c->received_host.len == received_host.len) { LM_DBG("Received host %.*s (search %.*s)\n", c->received_host.len, c->received_host.s, received_host.len, received_host.s); // Finally really compare the "received_host" if (!memcmp(c->received_host.s, received_host.s, received_host.len)) break; c = NULL; } } else { c = NULL; } } } } else { LM_WARN("No contact-header found\n"); } if ((c == NULL) && (is_registered_fallback2ip > 0)) { LM_WARN("Contact not found based on Contact-header, trying IP/Port/Proto\n"); received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); received_host.s = srcip; if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); } } asserted_identity = NULL; if (c) { p = c->head; while (p) { if (p->is_default == 1) asserted_identity = &p->public_identity; p = p->next; } } return c; }
/** * 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; }
static int fill_contact(struct pcontact_info* ci, struct sip_msg* m) { contact_body_t* cb = NULL; struct via_body* vb = NULL; unsigned short port, proto = 0; struct sip_msg* req = NULL; if(!ci) { LM_ERR("fill_contact() called with null ptr\n"); return -1; } memset(ci, 0, sizeof(struct pcontact_info)); if(m->first_line.type == SIP_REQUEST) { struct sip_uri uri; memset(&uri, 0, sizeof(struct sip_uri)); if(parse_uri(m->first_line.u.request.uri.s, m->first_line.u.request.uri.len, &uri)) { LM_ERR("Can't parse the request URI from first line\n"); return -1; } // populate host,port, aor in CI ci->via_host = uri.host; ci->via_port = uri.port_no ? uri.port_no : 5060; ci->via_prot = proto; ci->aor = m->first_line.u.request.uri; req = m; } else if(m->first_line.type == SIP_REPLY) { cb = cscf_parse_contacts(m); vb = cscf_get_ue_via(m); port = vb->port?vb->port:5060; proto = vb->proto; struct cell *t = tmb.t_gett(); if (!t || t == (void*) -1) { LM_ERR("fill_contact(): Reply without transaction\n"); return -1; } req = t->uas.request; cb = cscf_parse_contacts(req); if (!cb || (!cb->contacts)) { LM_ERR("fill_contact(): No contact headers\n"); return -1; } // populate CI with bare minimum ci->via_host = vb->host; ci->via_port = port; ci->via_prot = proto; ci->aor = cb->contacts->uri; } char* srcip = NULL; if((srcip = pkg_malloc(50)) == NULL) { LM_ERR("Error allocating memory for source IP address\n"); return -1; } ci->received_host.len = ip_addr2sbuf(&req->rcv.src_ip, srcip, 50); ci->received_host.s = srcip; ci->received_port = req->rcv.src_port; ci->received_proto = req->rcv.proto; // Set to default, if not set: if (ci->received_port == 0) ci->received_port = 5060; return 0; }
/** * Process the 401 response for REGISTER and creates the first Security-Associations. * Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER * could come over that one. * @param rpl - the 401 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_IPSec_401(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; str auth; struct hdr_field *hdr; str sec_cli,sec_srv={0,0}; str ck,ik; char ck_c[64],ik_c[64]; str ck_esp={ck_c,0},ik_esp={ik_c,0}; str alg,ealg; str alg_setkey,ealg_setkey; str tmp; unsigned int spi_uc,spi_us; unsigned int spi_pc,spi_ps; int port_uc,port_us; char cmd[256]; str ue; contact_body_t *contact; struct sip_uri uri; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No transactional request found.\n"); goto error; } auth = cscf_get_authenticate(rpl,&hdr); if (!auth.len){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No authorization header found.\n"); goto error; } sec_cli = cscf_get_security_client(req,&hdr); if (!sec_cli.len){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: No Security-Client header found.\n"); goto error; } /* first we look for CK, IK */ get_qparam(auth,s_ck,ck); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: CK: <%.*s>\n", ck.len,ck.s); get_qparam(auth,s_ik,ik); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: IK: <%.*s>\n", ik.len,ik.s); /* then for algorithms */ get_param(sec_cli,s_ealg,ealg); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Enc Algorithm: <%.*s>\n", ealg.len,ealg.s); get_param(sec_cli,s_alg,alg); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Int Algorithm: <%.*s>\n", alg.len,alg.s); /* and for spis */ get_param(sec_cli,s_spi_c,tmp); strtoint(tmp,spi_uc); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-C: %d\n", spi_uc); get_param(sec_cli,s_spi_s,tmp); strtoint(tmp,spi_us); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-S: %d\n", spi_us); /* and for ports */ get_param(sec_cli,s_port_c,tmp); strtoint(tmp,port_uc); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-C: %d\n", port_uc); get_param(sec_cli,s_port_s,tmp); strtoint(tmp,port_us); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-S: %d\n", port_us); contact = cscf_parse_contacts(req); if (!contact) { LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Message contains no Contact!\n"); goto error; } if (contact->contacts){ ue = contact->contacts->uri; if (parse_uri(ue.s,ue.len,&uri)){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error parsing uri <%.*s>\n",ue.len,ue.s); goto error; } ue = uri.host; if (uri.port_no==0) port_uc=5060; }else ue = req->via1->host; LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: UE IP: <%.*s> \n",ue.len,ue.s); spi_pc=get_next_spi(); spi_ps=get_next_spi(); 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":P_ipsec_401: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s); goto error; } /* try to add the Security-Server header */ sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n", ealg.len,ealg.s, alg.len,alg.s, spi_pc,spi_ps, pcscf_ipsec_port_c,pcscf_ipsec_port_s); sec_srv.len = strlen(cmd); sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } memcpy(sec_srv.s,cmd,sec_srv.len); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } /* run the IPSec script */ /* P_Inc_Req */ sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Req, ue.len,ue.s, port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, spi_ps, ealg_setkey.len,ealg_setkey.s, ck_esp.len,ck_esp.s, alg_setkey.len,alg_setkey.s, ik_esp.len,ik_esp.s); execute_cmd(cmd); /* save data into registrar */ save_contact_ipsec(req,rpl, spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us, ealg_setkey,ck_esp,alg_setkey,ik_esp); return 1; error: return 0; }
/** * get PContact-Structure for message * (search only once per Request) */ pcontact_t * getContactP(struct sip_msg* _m, udomain_t* _d) { ppublic_t * p; contact_body_t *b = 0; contact_t *ct; str received_host = {0, 0}; char srcip[50]; received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); received_host.s = srcip; if (_m->id != current_msg_id) { current_msg_id = _m->id; c = NULL; if (is_registered_fallback2ip == 2) { LM_DBG("Searching in usrloc for %.*s:%i (Proto %i)\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) { LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); } else { if (checkcontact(_m, c) != 0) { c = NULL; } } } if (c == NULL) { b = cscf_parse_contacts(_m); if (b && b->contacts) { for (ct = b->contacts; ct; ct = ct->next) { if (ul.get_pcontact(_d, &ct->uri, &received_host, _m->rcv.src_port, &c) == 0) { if (checkcontact(_m, c) != 0) { c = NULL; } else { break; } } } } else { LM_WARN("No contact-header found?!?\n"); } } if ((c == NULL) && (is_registered_fallback2ip == 1)) { LM_INFO("Contact not found based on Contact-header, trying IP/Port/Proto\n"); received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); received_host.s = srcip; if (ul.get_pcontact_by_src(_d, &received_host, _m->rcv.src_port, _m->rcv.proto, &c) == 1) { LM_DBG("No entry in usrloc for %.*s:%i (Proto %i) found!\n", received_host.len, received_host.s, _m->rcv.src_port, _m->rcv.proto); } else { if (checkcontact(_m, c) != 0) { c = NULL; } } } } asserted_identity = NULL; registration_contact = NULL; if (c) { registration_contact = &c->contact_user; p = c->head; while (p) { if (p->is_default == 1) asserted_identity = &p->public_identity; p = p->next; } } return c; }
/** * Save the contacts and their associated public ids. * @param rpl - the SIP Register 200 OK response that contains the Expire and Contact and P-associated-uri headers * @param _d - domain * @param _cflags - flags * @returns #CSCF_RETURN_TRUE if OK, #CSCF_RETURN_ERROR on error */ int save(struct sip_msg* _m, udomain_t* _d, int _cflags) { struct sip_msg* req; int expires_hdr = 0; contact_body_t* cb = 0; str *public_ids=0; int num_public_ids = 0; str *service_routes=0; int num_service_routes = 0; pv_elem_t *presentity_uri_pv; //get request from reply req = get_request_from_reply(_m); if (!req) { LM_ERR("Unable to get request from reply for REGISTER. No transaction\n"); goto error; } expires_hdr = cscf_get_expires_hdr(_m, 0); cb = cscf_parse_contacts(_m); if (!cb || (!cb->contacts && !cb->star)) { LM_DBG("No contact headers and not *\n"); goto error; } cscf_get_p_associated_uri(_m, &public_ids, &num_public_ids, 1); service_routes = cscf_get_service_route(_m, &num_service_routes, 1); //update contacts if (!update_contacts(req, _m, _d, cb->star, expires_hdr, public_ids, num_public_ids, service_routes, num_service_routes, 0)) { LM_ERR("failed to update pcontact\n"); goto error; } if(subscribe_to_reginfo == 1){ //use the first p_associated_uri - i.e. the default IMPU LM_DBG("Subscribe to reg event for primary p_associated_uri"); if(num_public_ids > 0){ //find the first routable (not a tel: URI and use that that presentity) //if you can not find one then exit int i = 0; int found_presentity_uri=0; while (i < num_public_ids && found_presentity_uri == 0) { //check if public_id[i] is NOT a tel URI - if it isn't then concert to pv format and set found presentity_uri to 1 if (strncasecmp(public_ids[i].s,"tel:",4)==0) { LM_DBG("This is a tel URI - it is not routable so we don't use it to subscribe"); i++; } else { //convert primary p_associated_uri to pv_elem_t if(pv_parse_format(&public_ids[i], &presentity_uri_pv)<0) { LM_ERR("wrong format[%.*s]\n",public_ids[i].len, public_ids[i].s); goto error; } found_presentity_uri=1; } } if(found_presentity_uri!=1){ LM_ERR("Could not find routable URI in p_assoiated_uri list - failed to subscribe"); goto error; } }else{ //Now some how check if there is a pua record and what the presentity uri is from there - if nothing there LM_DBG("No p_associated_uri in 200 OK this must be a de-register - we ignore this - will unsubscribe when the notify is received"); goto done; } reginfo_subscribe_real(_m, presentity_uri_pv, service_routes, subscription_expires); pv_elem_free_all(presentity_uri_pv); } done: if (public_ids && public_ids->s) pkg_free(public_ids); if (service_routes && service_routes->s) pkg_free(service_routes); return 1; error: if (public_ids && public_ids->s) pkg_free(public_ids); if (service_routes && service_routes->s) pkg_free(service_routes); return -1; }
/** * Save contact based on REGISTER request. this will be a pending save, until we receive response * from SCSCF. If no response after pending_timeout seconds, the contacts is removed. Can only be used from REQUEST ROUTE */ int save_pending(struct sip_msg* _m, udomain_t* _d) { contact_body_t* cb = 0; int cexpires = 0; pcontact_t* pcontact; contact_t* c; struct pcontact_info ci; struct via_body* vb; unsigned short port, proto; int_str val; struct sip_uri parsed_received; char srcip[50]; memset(&ci, 0, sizeof(struct pcontact_info)); vb = cscf_get_ue_via(_m); port = vb->port?vb->port:5060; proto = vb->proto; cb = cscf_parse_contacts(_m); if (!cb || (!cb->contacts)) { LM_ERR("No contact headers\n"); goto error; } c = cb->contacts; //TODO: need support for multiple contacts - currently assume one contact //make sure this is not a de-registration int expires_hdr = cscf_get_expires_hdr(_m, 0); if (expires_hdr < 0) { //no global header we have to check the contact expiry if (c && c->expires && c->expires->body.len) { str2int(&(c->expires->body), (unsigned int*) &cexpires); } if (!cexpires){ //assume de-registration LM_DBG("not doing pending reg on de-registration\n"); return 1; } } pcscf_act_time(); int local_time_now = time_now; int expires = calc_contact_expires(c, expires_hdr, local_time_now); if (expires <= 0) { LM_DBG("not doing pending reg on de-registration\n"); return 1; } LM_DBG("Save Pending"); LM_DBG("contact requesting to expire in %d seconds\n", expires-local_time_now); /*populate CI with bare minimum*/ ci.via_host = vb->host; ci.via_port = port; ci.via_prot = proto; ci.aor = c->uri; ci.num_public_ids=0; ci.num_service_routes=0; ci.expires=local_time_now + pending_reg_expires; ci.reg_state=PCONTACT_ANY; ci.searchflag=SEARCH_RECEIVED; //we want to make sure we are very specific with this search to make sure we get the correct contact to put into reg_pending. // Received Info: First try AVP, otherwise simply take the source of the request: memset(&val, 0, sizeof(int_str)); if (rcv_avp_name.n != 0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) { if (val.s.len > RECEIVED_MAX_SIZE) { LM_ERR("received too long\n"); goto error; } if (parse_uri(val.s.s, val.s.len, &parsed_received) < 0) { LM_DBG("Error parsing Received URI <%.*s>\n", val.s.len, val.s.s); goto error; } ci.received_host = parsed_received.host; ci.received_port = parsed_received.port_no; ci.received_proto = parsed_received.proto; } else { ci.received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip)); ci.received_host.s = srcip; ci.received_port = _m->rcv.src_port; ci.received_proto = _m->rcv.proto; } // Set to default, if not set: if (ci.received_port == 0) ci.received_port = 5060; ul.lock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot); if (ul.get_pcontact(_d, &ci, &pcontact) != 0) { //need to insert new contact LM_DBG("Adding pending pcontact: <%.*s>\n", c->uri.len, c->uri.s); ci.reg_state=PCONTACT_REG_PENDING; if (ul.insert_pcontact(_d, &c->uri, &ci, &pcontact) != 0) { LM_ERR("Failed inserting new pcontact\n"); } else { LM_DBG("registering for UL callback\n"); ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE | PCSCF_CONTACT_UPDATE, callback_pcscf_contact_cb, NULL); } } else { //contact already exists - update LM_DBG("Contact already exists - not doing anything for now\n"); } ul.unlock_udomain(_d, &ci.via_host, ci.via_port, ci.via_prot); return 1; error: LM_DBG("Error saving pending contact\n"); return -1; }
/* Wrapper to send AAR from config file - only used for registration */ static int w_rx_aar_register(struct sip_msg *msg, char* route, char* str1, char* bar) { int ret = CSCF_RETURN_ERROR; struct pcontact_info ci; struct cell *t; contact_t* c; struct hdr_field* h; pcontact_t* pcontact; contact_body_t* cb = 0; AAASession* auth; rx_authsessiondata_t* rx_regsession_data_p; cfg_action_t* cfg_action = 0; str route_name; char* p; int aar_sent = 0; saved_transaction_local_t* local_data = 0; //data to be shared across all async calls saved_transaction_t* saved_t_data = 0; //data specific to each contact's AAR async call if (fixup_get_svalue(msg, (gparam_t*) route, &route_name) != 0) { LM_ERR("no async route block for assign_server_unreg\n"); return -1; } LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s); int ri = route_get(&main_rt, route_name.s); if (ri < 0) { LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s); return -1; } cfg_action = main_rt.rlist[ri]; if (cfg_action == NULL) { LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s); return -1; } udomain_t* domain_t = (udomain_t*) str1; int is_rereg = 0; //is this a reg/re-reg LM_DBG("Rx AAR Register called\n"); //create the default return code AVP create_return_code(ret); memset(&ci, 0, sizeof (struct pcontact_info)); /** If this is a response then let's check the status before we try and do an AAR. * We will only do AAR for register on success response and of course if message is register */ if (msg->first_line.type == SIP_REPLY) { //check this is a response to a register /* Get the SIP request from this transaction */ t = tmb.t_gett(); if (!t) { LM_ERR("Cannot get transaction for AAR based on SIP Request\n"); goto error; } if ((strncmp(t->method.s, "REGISTER", 8) != 0)) { LM_ERR("Method is not a response to a REGISTER\n"); goto error; } if (msg->first_line.u.reply.statuscode < 200 || msg->first_line.u.reply.statuscode >= 300) { LM_DBG("Message is not a 2xx OK response to a REGISTER\n"); goto error; } tmb.t_release(msg); } else { //SIP Request /* in case of request make sure it is a REGISTER */ if (msg->first_line.u.request.method_value != METHOD_REGISTER) { LM_DBG("This is not a register request\n"); goto error; } if ((cscf_get_max_expires(msg, 0) == 0)) { //if ((cscf_get_expires(msg) == 0)) { LM_DBG("This is a de registration\n"); LM_DBG("We ignore it as these are dealt with by usrloc callbacks \n"); create_return_code(CSCF_RETURN_TRUE); return CSCF_RETURN_TRUE; } } //before we continue, make sure we have a transaction to work with (viz. cdp async) t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { if (tmb.t_newtran(msg) < 0) { LM_ERR("cannot create the transaction for UAR async\n"); return CSCF_RETURN_ERROR; } t = tmb.t_gett(); if (t == NULL || t == T_UNDEFINED) { LM_ERR("cannot lookup the transaction\n"); return CSCF_RETURN_ERROR; } } saved_t_data = (saved_transaction_t*) shm_malloc(sizeof (saved_transaction_t)); if (!saved_t_data) { LM_ERR("Unable to allocate memory for transaction data, trying to send AAR\n"); return CSCF_RETURN_ERROR; } memset(saved_t_data, 0, sizeof (saved_transaction_t)); saved_t_data->act = cfg_action; saved_t_data->domain = domain_t; saved_t_data->lock = lock_alloc(); if (saved_t_data->lock == NULL) { LM_ERR("unable to allocate init lock for saved_t_transaction reply counter\n"); return CSCF_RETURN_ERROR; } if (lock_init(saved_t_data->lock) == NULL) { LM_ERR("unable to init lock for saved_t_transaction reply counter\n"); return CSCF_RETURN_ERROR; } LM_DBG("Suspending SIP TM transaction\n"); if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) { LM_ERR("failed to suspend the TM processing\n"); free_saved_transaction_global_data(saved_t_data); return CSCF_RETURN_ERROR; } LM_DBG("Successfully suspended transaction\n"); //now get the contacts in the REGISTER and do AAR for each one. cb = cscf_parse_contacts(msg); if (!cb || (!cb->contacts && !cb->star)) { LM_DBG("No contact headers in Register message\n"); goto error; } lock_get(saved_t_data->lock); //we lock here to make sure we send all requests before processing replies asynchronously for (h = msg->contact; h; h = h->next) { if (h->type == HDR_CONTACT_T && h->parsed) { for (c = ((contact_body_t*) h->parsed)->contacts; c; c = c->next) { ul.lock_udomain(domain_t, &c->uri); if (ul.get_pcontact(domain_t, &c->uri, &pcontact) != 0) { LM_DBG("This contact does not exist in PCSCF usrloc - error in cfg file\n"); ul.unlock_udomain(domain_t, &c->uri); lock_release(saved_t_data->lock); goto error; } else if (pcontact->reg_state == PCONTACT_REG_PENDING || pcontact->reg_state == PCONTACT_REGISTERED) { //NEW reg request LM_DBG("Contact [%.*s] exists and is in state PCONTACT_REG_PENDING or PCONTACT_REGISTERED\n" , pcontact->aor.len, pcontact->aor.s); //get IP address from contact struct sip_uri puri; if (parse_uri(c->uri.s, c->uri.len, &puri) < 0) { LM_ERR("failed to parse Contact\n"); ul.unlock_udomain(domain_t, &c->uri); lock_release(saved_t_data->lock); goto error; } LM_DBG("Parsed URI of from host is [%.*s]\n", puri.host.len, puri.host.s); uint16_t ip_version = AF_INET; //TODO IPv6!!!? //check for existing Rx session if (pcontact->rx_session_id.len > 0 && pcontact->rx_session_id.s && (auth = cdpb.AAAGetAuthSession(pcontact->rx_session_id))) { LM_DBG("Rx session already exists for this user\n"); if (memcmp(pcontact->rx_session_id.s, auth->id.s, auth->id.len) != 0) { LM_ERR("Rx session mismatch when URI is [%.*s].......Aborting\n", puri.host.len, puri.host.s); if (auth) cdpb.AAASessionsUnlock(auth->hash); lock_release(saved_t_data->lock); goto error; } //re-registration - update auth lifetime auth->u.auth.lifetime = time(NULL) + rx_auth_expiry; is_rereg = 1; } else { LM_DBG("Creating new Rx session for contact <%.*s>\n", pcontact->aor.len, pcontact->aor.s); int ret = create_new_regsessiondata(domain_t->name, &pcontact->aor, &rx_regsession_data_p); if (!ret) { LM_ERR("Unable to create regsession data parcel when URI is [%.*s]...Aborting\n", puri.host.len, puri.host.s); ul.unlock_udomain(domain_t, &c->uri); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } lock_release(saved_t_data->lock); goto error; } auth = cdpb.AAACreateClientAuthSession(1, callback_for_cdp_session, rx_regsession_data_p); //returns with a lock if (!auth) { LM_ERR("Rx: unable to create new Rx Reg Session when URI is [%.*s]\n", puri.host.len, puri.host.s); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } ul.unlock_udomain(domain_t, &c->uri); if (auth) cdpb.AAASessionsUnlock(auth->hash); if (rx_regsession_data_p) { shm_free(rx_regsession_data_p); rx_regsession_data_p = 0; } lock_release(saved_t_data->lock); goto error; } } //we are ready to send the AAR async. lets save the local data data int local_data_len = sizeof (saved_transaction_local_t) + c->uri.len + auth->id.len; local_data = shm_malloc(local_data_len); if (!local_data) { LM_ERR("unable to alloc memory for local data, trying to send AAR Register\n"); lock_release(saved_t_data->lock); goto error; } memset(local_data, 0, local_data_len); local_data->is_rereg = is_rereg; local_data->global_data = saved_t_data; p = (char*) (local_data + 1); local_data->contact.s = p; local_data->contact.len = c->uri.len; memcpy(p, c->uri.s, c->uri.len); p += c->uri.len; local_data->auth_session_id.s = p; local_data->auth_session_id.len = auth->id.len; memcpy(p, auth->id.s, auth->id.len); p += auth->id.len; if (p != (((char*) local_data) + local_data_len)) { LM_CRIT("buffer overflow\n"); free_saved_transaction_data(local_data); goto error; } LM_DBG("Calling send aar register"); //TODOD remove - no longer user AOR parm //ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, &c->uri, local_data); //returns a locked rx auth object ret = rx_send_aar_register(msg, auth, &puri.host, &ip_version, local_data); //returns a locked rx auth object ul.unlock_udomain(domain_t, &c->uri); if (!ret) { LM_ERR("Failed to send AAR\n"); lock_release(saved_t_data->lock); free_saved_transaction_data(local_data); //free the local data becuase the CDP async request was not successful (we must free here) goto error; } else { aar_sent = 1; //before we send - bump up the reply counter saved_t_data->answers_not_received++; //we dont need to lock as we already hold the lock above } } else { //contact exists - this is a re-registration, for now we just ignore this LM_DBG("This contact exists and is not in state REGISTER PENDING - we assume re (or de) registration and ignore\n"); ul.unlock_udomain(domain_t, &c->uri); //now we loop for any other contacts. } } } else { if (h->type == HDR_CONTACT_T) { //means we couldnt parse the contact - this is an error LM_ERR("Failed to parse contact header\n"); lock_release(saved_t_data->lock); goto error; } } } //all requests sent at this point - we can unlock the reply lock lock_release(saved_t_data->lock); /*if we get here, we have either: * 1. Successfully sent AAR's for ALL contacts, or * 2. haven't needed to send ANY AAR's for ANY contacts */ if (aar_sent) { LM_DBG("Successful async send of AAR\n"); return CSCF_RETURN_BREAK; //on success we break - because rest of cfg file will be executed by async process } else { create_return_code(CSCF_RETURN_TRUE); tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); if (saved_t_data) { free_saved_transaction_global_data(saved_t_data); //no aar sent so we must free the global data } //return CSCF_RETURN_ERROR; return CSCF_RETURN_TRUE; } error: LM_ERR("Error trying to send AAR\n"); if (!aar_sent) { tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel); if (saved_t_data) { free_saved_transaction_global_data(saved_t_data); //only free global data if no AARs were sent. if one was sent we have to rely on the callback (CDP) to free //otherwise the callback will segfault } } return CSCF_RETURN_ERROR; //return CSCF_RETURN_FALSE; }