/*! \brief * Fills the common part (for all contacts) of the info structure */ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, unsigned int _flags) { static ucontact_info_t ci; static str no_ua = str_init("n/a"); static str callid; static str path_received = {0,0}; static str path; static str received = {0,0}; static int received_found; static unsigned int allowed, allow_parsed; static struct sip_msg *m = 0; int_str val; if (_m!=0) { memset( &ci, 0, sizeof(ucontact_info_t)); /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); if (callid.len > CALLID_MAX_SIZE) { rerrno = R_CALLID_LEN; LM_ERR("callid too long\n"); goto error; } ci.callid = &callid; /* Get CSeq number of the message */ if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) { rerrno = R_INV_CSEQ; LM_ERR("failed to convert cseq number\n"); goto error; } /* set received socket */ if ( _flags®_SAVE_SOCKET_FLAG) { ci.sock = get_sock_hdr(_m); if (ci.sock==0) ci.sock = _m->rcv.bind_address; } else { ci.sock = _m->rcv.bind_address; } /* additional info from message */ if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent && _m->user_agent->body.len>0 && _m->user_agent->body.len<UA_MAX_SIZE) { ci.user_agent = &_m->user_agent->body; } else { ci.user_agent = &no_ua; } /* extract Path headers */ if ( _flags®_SAVE_PATH_FLAG ) { if (build_path_vector(_m, &path, &path_received, _flags) < 0) { rerrno = R_PARSE_PATH; goto error; } if (path.len && path.s) { ci.path = &path; /* save in msg too for reply */ if (set_path_vector(_m, &path) < 0) { rerrno = R_PARSE_PATH; goto error; } } } ci.last_modified = act_time; /* set flags */ ci.flags = _f; ci.cflags = getb0flags(); /* get received */ if (path_received.len && path_received.s) { ci.cflags |= ul.nat_flag; ci.received = path_received; } allow_parsed = 0; /* not parsed yet */ received_found = 0; /* not found yet */ m = _m; /* remember the message */ } if(_c!=0) { /* Calculate q value of the contact */ if (calc_contact_q(_c->q, &ci.q) < 0) { rerrno = R_INV_Q; LM_ERR("failed to calculate q\n"); goto error; } /* set expire time */ ci.expires = _e; /* Get methods of contact */ if (_c->methods) { if (parse_methods(&(_c->methods->body), &ci.methods) < 0) { rerrno = R_PARSE; LM_ERR("failed to parse contact methods\n"); goto error; } } else { /* check on Allow hdr */ if (allow_parsed == 0) { if (m && parse_allow( m ) != -1) { allowed = get_allow_methods(m); } else { allowed = ALL_METHODS; } allow_parsed = 1; } ci.methods = allowed; } /* get received */ if (ci.received.len==0) { if (_c->received) { ci.received = _c->received->body; } else { if (received_found==0) { memset(&val, 0, sizeof(int_str)); if (rcv_avp_name>=0 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0) && val.s.len > 0) { if (val.s.len>RECEIVED_MAX_SIZE) { rerrno = R_CONTACT_LEN; LM_ERR("received too long\n"); goto error; } received = val.s; } else { received.s = 0; received.len = 0; } received_found = 1; } ci.received = received; } } } return &ci; error: return 0; }
/*! \brief * Fills the common part (for all contacts) of the info structure */ static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, int _use_regid) { static ucontact_info_t ci; static str no_ua = str_init("n/a"); static str callid; static str path_received = {0,0}; static str path; static str received = {0,0}; static int received_found; static unsigned int allowed, allow_parsed; static struct sip_msg *m = 0; int_str val; if (_m!=0) { memset( &ci, 0, sizeof(ucontact_info_t)); /* Get callid of the message */ callid = _m->callid->body; trim_trailing(&callid); if (callid.len > CALLID_MAX_SIZE) { rerrno = R_CALLID_LEN; LM_ERR("callid too long\n"); goto error; } ci.callid = &callid; /* Get CSeq number of the message */ if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) { rerrno = R_INV_CSEQ; LM_ERR("failed to convert cseq number\n"); goto error; } /* set received socket */ if (_m->flags&sock_flag) { ci.sock = get_sock_val(_m); if (ci.sock==0) ci.sock = _m->rcv.bind_address; } else { ci.sock = _m->rcv.bind_address; } /* set tcp connection id */ if (_m->rcv.proto==PROTO_TCP || _m->rcv.proto==PROTO_TLS || _m->rcv.proto==PROTO_WS || _m->rcv.proto==PROTO_WSS) { ci.tcpconn_id = _m->rcv.proto_reserved1; } else { ci.tcpconn_id = -1; } /* additional info from message */ if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent && _m->user_agent->body.len>0 && _m->user_agent->body.len<MAX_UA_SIZE) { ci.user_agent = &_m->user_agent->body; } else { ci.user_agent = &no_ua; } /* extract Path headers */ if (path_enabled) { if (build_path_vector(_m, &path, &path_received) < 0) { rerrno = R_PARSE_PATH; goto error; } if (path.len && path.s) { ci.path = &path; if (path_mode != PATH_MODE_OFF) { /* save in msg too for reply */ if (set_path_vector(_m, &path) < 0) { rerrno = R_PARSE_PATH; goto error; } } } } ci.last_modified = act_time; /* set flags */ ci.flags = _f; getbflagsval(0, &ci.cflags); /* get received */ if (path_received.len && path_received.s) { ci.cflags |= ul.nat_flag; ci.received = path_received; } allow_parsed = 0; /* not parsed yet */ received_found = 0; /* not found yet */ m = _m; /* remember the message */ } else { memset( &ci.instance, 0, sizeof(str)); } if(_c!=0) { /* hook uri address - should be more than 'sip:' chars */ if(_c->uri.s!=NULL && _c->uri.len>4) ci.c = &_c->uri; /* Calculate q value of the contact */ if (m && m->id == q_override_msg_id) { ci.q = q_override_value; } else if (calc_contact_q(_c->q, &ci.q) < 0) { rerrno = R_INV_Q; LM_ERR("failed to calculate q\n"); goto error; } /* set expire time */ ci.expires = _e; /* Get methods of contact */ if (_c->methods) { if (parse_methods(&(_c->methods->body), &ci.methods) < 0) { rerrno = R_PARSE; LM_ERR("failed to parse contact methods\n"); goto error; } } else { /* check on Allow hdr */ if (allow_parsed == 0) { if (m && parse_allow( m ) != -1) { allowed = get_allow_methods(m); } else { allowed = ALL_METHODS; } allow_parsed = 1; } ci.methods = allowed; } /* get received */ if (ci.received.len==0) { if (_c->received) { ci.received = _c->received->body; } else { if (received_found==0) { 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) { rerrno = R_CONTACT_LEN; LM_ERR("received too long\n"); goto error; } received = val.s; } else { received.s = 0; received.len = 0; } received_found = 1; } ci.received = received; } } if(_c->instance!=NULL && _c->instance->body.len>0) ci.instance = _c->instance->body; if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) { if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0) { LM_ERR("invalid reg-id value\n"); goto error; } } if(sruid_next(&_reg_sruid)<0) goto error; ci.ruid = _reg_sruid.uid; LM_DBG("generated ruid is: %.*s\n", ci.ruid.len, ci.ruid.s); } return &ci; error: return 0; }
/** * Handle third party registration * @param msg - the SIP REGISTER message * @param m - the isc_match that matched with info about where to forward it * @param mark - the isc_mark that should be used to mark the message * @returns #ISC_RETURN_TRUE if allowed, #ISC_RETURN_FALSE if not */ int isc_third_party_reg(struct sip_msg *msg, isc_match *m, isc_mark *mark) { r_third_party_registration r; str path, path_received; int expires = 0; str req_uri = {0, 0}; str to = {0, 0}; str pvni = {0, 0}; str pani = {0, 0}; str cv = {0, 0}; struct hdr_field *hdr; LM_DBG("isc_third_party_reg: Enter\n"); /* Set Request Uri to IFC matching server name */ req_uri.len = m->server_name.len; req_uri.s = m->server_name.s; /* Get To header*/ to = cscf_get_public_identity(msg); /*TODO - check if the min/max expires is in the acceptable limits * this does not work correctly if the user has multiple contacts * and register/deregisters them individually!!! */ expires = cscf_get_max_expires(msg, 0); /* Get P-Visited-Network-Id header */ pvni = cscf_get_visited_network_id(msg, &hdr); /* Get P-Access-Network-Info header */ pani = cscf_get_access_network_info(msg, &hdr); if (build_path_vector(msg, &path, &path_received) < 0) { LM_ERR("Failed to parse PATH header for third-party reg\n"); return ISC_RETURN_FALSE; } LM_DBG("PATH header in REGISTER is [%.*s]\n", path.len, path.s); /* Get P-Charging-Vector header */ /* Just forward the charging header received from P-CSCF */ /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */ cv = cscf_get_charging_vector(msg, &hdr); if (req_uri.s) { memset(&r, 0, sizeof (r_third_party_registration)); r.req_uri = req_uri; r.to = to; r.from = isc_my_uri_sip; r.pvni = pvni; r.pani = pani; r.cv = cv; r.service_info = m->service_info; r.path = path; if (expires <= 0) r_send_third_party_reg(&r, 0); else r_send_third_party_reg(&r, expires + isc_expires_grace); return ISC_RETURN_TRUE; } else { return ISC_RETURN_FALSE; } }
/** * Handle third party registration * @param msg - the SIP REGISTER message * @param m - the isc_match that matched with info about where to forward it * @param mark - the isc_mark that should be used to mark the message * @returns #ISC_RETURN_TRUE if allowed, #ISC_RETURN_FALSE if not */ int isc_third_party_reg(struct sip_msg *msg, isc_match *m, isc_mark *mark, udomain_t* d) { r_third_party_registration r; str path, path_received; int expires = 0; str req_uri = {0, 0}; str to = {0, 0}; str pvni = {0, 0}; str pani = {0, 0}; str cv = {0, 0}; str s = {0, 0}; impurecord_t *p; struct hdr_field *hdr; LM_DBG("isc_third_party_reg: Enter\n"); /* Set Request Uri to IFC matching server name */ req_uri.len = m->server_name.len; req_uri.s = m->server_name.s; /* Get To header*/ to = cscf_get_public_identity(msg); if (cscf_get_originating_user(msg, &s)) { isc_ulb.lock_udomain(d, &s); if ( isc_ulb.get_impurecord(d,&s,&p) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to get IMPU domain from usrloc\n"); goto no_pai; } if ( build_p_associated_uri(p->s) != 0) { isc_ulb.unlock_udomain(d, &s); LM_ERR("Failed to build P-Associated URI for 3rd party reg\n"); goto no_pai; } isc_ulb.unlock_udomain(d, &s); } /*TODO - check if the min/max expires is in the acceptable limits * this does not work correctly if the user has multiple contacts * and register/deregisters them individually!!! */ no_pai: expires = cscf_get_max_expires(msg, 0); /* Get P-Visited-Network-Id header */ pvni = cscf_get_visited_network_id(msg, &hdr); /* Get P-Access-Network-Info header */ pani = cscf_get_access_network_info(msg, &hdr); if (build_path_vector(msg, &path, &path_received) < 0) { LM_ERR("Failed to parse PATH header for third-party reg\n"); return ISC_RETURN_FALSE; } LM_DBG("PATH header in REGISTER is [%.*s]\n", path.len, path.s); /* Get P-Charging-Vector header */ /* Just forward the charging header received from P-CSCF */ /* Todo: implement also according to TS 24.229, chap 5.4.1.7 */ cv = cscf_get_charging_vector(msg, &hdr); if (req_uri.s) { memset(&r, 0, sizeof (r_third_party_registration)); r.req_uri = req_uri; r.to = to; r.from = isc_my_uri_sip; r.pvni = pvni; r.pani = pani; r.cv = cv; if (m->service_info.s && m->service_info.len) { r.body.content_type = CT_SERVICE_INFO; r.body.content = m->service_info; } else if (m->include_register_request) { r.body.content_type = CT_REGISTER_REQ; r.body.content.s = msg->first_line.u.request.method.s; r.body.content.len = msg->len; } else if (m->include_register_response) { struct bookmark dummy_bm; r.body.content_type = CT_REGISTER_RESP; r.body.content.s = build_res_buf_from_sip_req(200, ®_resp_200OK, 0, msg, (unsigned int*)&r.body.content.len, &dummy_bm); if (!r.body.content.s) { LM_DBG("response building failed for body of third party register request"); r.body.content_type = CT_NONE; } } else { r.body.content_type = CT_NONE; } r.path = path; if (expires <= 0) r_send_third_party_reg(&r, 0); else r_send_third_party_reg(&r, expires + isc_expires_grace); return ISC_RETURN_TRUE; } else { return ISC_RETURN_FALSE; } }