int via_diff(struct sip_msg *req,struct sip_msg *resp) { struct hdr_field *hf; struct via_body *vb; int i,j,k; i=j=k=0; /* count how many via bodies come in the response*/ for(hf=resp->h_via1;hf;hf=next_sibling_hdr(hf)){ if(!hf->parsed){ if((vb=pkg_malloc(sizeof(struct via_body)))==0){ LM_ERR("Out of mem in via_diff!!\n"); return -1; } memset(vb,0,sizeof(struct via_body)); if(parse_via(hf->body.s,hf->body.s+hf->body.len+1,vb)==0){ LM_ERR("Unable to parse via in via_diff!\n"); pkg_free(vb); return -1; } hf->parsed=vb; j=1; } for(vb=hf->parsed;vb;vb=vb->next){ i++; } if(j){ free_via_list((struct via_body*)hf->parsed); hf->parsed=NULL; j=0; } } j=0; /* count how many via bodies were in the orig. request*/ for(hf=req->h_via1;hf;hf=next_sibling_hdr(hf)){ if(!hf->parsed){ if((vb=pkg_malloc(sizeof(struct via_body)))==0){ goto error; } memset(vb,0,sizeof(struct via_body)); if(parse_via(hf->body.s,hf->body.s+hf->body.len+1,vb)==0){ goto error; } hf->parsed=vb; j=1; } for(vb=hf->parsed;vb;vb=vb->next){ k++; } if(j){ free_via_list((struct via_body*)hf->parsed); hf->parsed=NULL; j=0; } } return i-k; error: return -1; }
int th_mask_record_route(sip_msg_t *msg) { hdr_field_t *hdr; struct lump* l; int i; rr_t *rr; str out; if(msg->record_route==NULL) { LM_DBG("no record route header\n"); return 0; } hdr = msg->record_route; i = 0; while(hdr!=NULL) { if (parse_rr(hdr) < 0) { LM_ERR("failed to parse RR\n"); return -1; } rr =(rr_t*)hdr->parsed; while(rr) { i++; if(i!=1) { out.s = th_mask_encode(rr->nameaddr.uri.s, rr->nameaddr.uri.len, &th_uri_prefix, &out.len); if(out.s==NULL) { LM_ERR("cannot encode r-r %d\n", i); return -1; } l=del_lump(msg, rr->nameaddr.uri.s-msg->buf, rr->nameaddr.uri.len, 0); if (l==0) { LM_ERR("failed deleting r-r [%d]\n", i); pkg_free(out.s); return -1; } if (insert_new_lump_after(l, out.s, out.len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(out.s); return -1; } } rr = rr->next; } hdr = next_sibling_hdr(hdr); } return 0; }
/*! \brief * Combines all Path HF bodies into one string. */ int build_path_vector(struct sip_msg *_m, str *path, str *received) { static char buf[MAX_PATH_SIZE]; char *p; struct hdr_field *hdr; struct sip_uri puri; rr_t *route = 0; path->len = 0; path->s = 0; received->s = 0; received->len = 0; if (parse_headers(_m, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse the message\n"); goto error; } for (hdr = _m->path, p = buf; hdr; hdr = next_sibling_hdr(hdr)) { /* check for max. Path length */ if (p - buf + hdr->body.len + 1 >= MAX_PATH_SIZE) { LM_ERR("Overall Path body exceeds max. length of %d\n", MAX_PATH_SIZE); goto error; } if (p != buf) *(p++) = ','; memcpy(p, hdr->body.s, hdr->body.len); p += hdr->body.len; } if (p != buf) { /* check if next hop is a loose router */ if (parse_rr_body(buf, p - buf, &route) < 0) { LM_ERR("failed to parse Path body, no head found\n"); goto error; } if (parse_uri(route->nameaddr.uri.s, route->nameaddr.uri.len, &puri) < 0) { LM_ERR("failed to parse the first Path URI\n"); goto error; } if (!puri.lr.s) { LM_ERR("first Path URI is not a loose-router, not supported\n"); goto error; } free_rr(&route); } path->s = buf; path->len = p - buf; return 0; error: if (route) free_rr(&route); return -1; }
int th_mask_via(sip_msg_t *msg) { hdr_field_t *hdr; struct via_body *via; struct lump* l; int i; str out; int vlen; i=0; for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr)) { for(via=(struct via_body*)hdr->parsed; via; via=via->next) { i++; LM_DBG("=======via[%d]\n", i); LM_DBG("hdr: [%.*s]\n", via->hdr.len, via->hdr.s); vlen = th_skip_rw(via->name.s, via->bsize); LM_DBG("body: %d: [%.*s]\n", vlen, vlen, via->name.s); if(i!=1) { out.s = th_mask_encode(via->name.s, vlen, &th_via_prefix, &out.len); if(out.s==NULL) { LM_ERR("cannot encode via %d\n", i); return -1; } LM_DBG("+body: %d: [%.*s]\n", out.len, out.len, out.s); l=del_lump(msg, via->name.s-msg->buf, vlen, 0); if (l==0) { LM_ERR("failed deleting via [%d]\n", i); pkg_free(out.s); return -1; } if (insert_new_lump_after(l, out.s, out.len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(out.s); return -1; } } } } return 0; }
/*! * Parse all Supported headers */ int parse_supported( struct sip_msg *msg) { unsigned int supported; struct hdr_field *hdr; struct option_tag_body *sb; /* maybe the header is already parsed! */ if (msg->supported && msg->supported->parsed) return 0; /* parse to the end in order to get all SUPPORTED headers */ if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->supported) return -1; /* bad luck! :-( - we have to parse them */ supported = 0; for( hdr=msg->supported ; hdr ; hdr=next_sibling_hdr(hdr)) { if (hdr->parsed) { supported |= ((struct option_tag_body*)hdr->parsed)->option_tags; continue; } sb = (struct option_tag_body*)pkg_malloc(sizeof(struct option_tag_body)); if (sb == 0) { LM_ERR("out of pkg_memory\n"); return -1; } parse_option_tag_body(&(hdr->body), &(sb->option_tags)); sb->hfree = hf_free_option_tag; sb->option_tags_all = 0; hdr->parsed = (void*)sb; supported |= sb->option_tags; } ((struct option_tag_body*)msg->supported->parsed)->option_tags_all = supported; return 0; }
/*! * Parse all Require headers */ int parse_require( struct sip_msg *msg) { unsigned int require; struct hdr_field *hdr; struct option_tag_body *rb; /* maybe the header is already parsed! */ if (msg->require && msg->require->parsed) return 0; /* parse to the end in order to get all SUPPORTED headers */ if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->require) return -1; /* bad luck! :-( - we have to parse them */ require = 0; for( hdr=msg->require ; hdr ; hdr=next_sibling_hdr(hdr)) { if (hdr->parsed) { require |= ((struct option_tag_body*)hdr->parsed)->option_tags; continue; } rb = (struct option_tag_body*)pkg_malloc(sizeof(struct option_tag_body)); if (rb == 0) { LM_ERR("out of pkg_memory\n"); return -1; } parse_option_tag_body(&(hdr->body), &(rb->option_tags)); rb->hfree = hf_free_option_tag; rb->option_tags_all = 0; hdr->parsed = (void*)rb; require |= rb->option_tags; } ((struct option_tag_body*)msg->require->parsed)->option_tags_all = require; return 0; }
/*! \brief * Combines all Path HF bodies into one string. */ int build_path_vector(struct sip_msg *_m, str *path, str *received) { static char buf[MAX_PATH_BUFFER]; char *p; struct hdr_field *hdr; struct sip_uri puri; rr_t *route = 0; path->len = 0; path->s = 0; received->s = 0; received->len = 0; if(parse_headers(_m, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse the message\n"); goto error; } for( hdr=_m->path,p=buf ; hdr ; hdr = next_sibling_hdr(hdr)) { /* check for max. Path length */ if( p-buf+hdr->body.len+1 >= MAX_PATH_BUFFER) { LM_ERR("Overall Path body exceeds max. length of %d - trying to add header [%.*s] and already have [%.*s]\n", MAX_PATH_BUFFER, hdr->body.len, hdr->body.s, (int)(p-buf), buf); goto error; } if(p!=buf) *(p++) = ','; memcpy( p, hdr->body.s, hdr->body.len); p += hdr->body.len; } if (p!=buf) { /* check if next hop is a loose router */ if (parse_rr_body( buf, p-buf, &route) < 0) { LM_ERR("failed to parse Path body, no head found\n"); goto error; } if (parse_uri(route->nameaddr.uri.s,route->nameaddr.uri.len,&puri)<0){ LM_ERR("failed to parse the first Path URI\n"); goto error; } if (!puri.lr.s) { LM_ERR("first Path URI is not a loose-router, not supported\n"); goto error; } if (path_use_params) { param_hooks_t hooks; param_t *params; if (parse_params(&(puri.params),CLASS_CONTACT,&hooks,¶ms)!=0){ LM_ERR("failed to parse parameters of first hop\n"); goto error; } if (hooks.contact.received) *received = hooks.contact.received->body; /*for (;params; params = params->next) { if (params->type == P_RECEIVED) { *received = hooks.contact.received->body; break; } }*/ free_params(params); } free_rr(&route); } path->s = buf; path->len = p-buf; return 0; error: if(route) free_rr(&route); return -1; }
int tps_pack_request(sip_msg_t *msg, tps_data_t *ptsd) { hdr_field_t *hdr; via_body_t *via; rr_t *rr; int i; int vlen; if(ptsd->cp==NULL) { ptsd->cp = ptsd->cbuf; } i = 0; for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr)) { for(via=(struct via_body*)hdr->parsed; via; via=via->next) { i++; vlen = tps_skip_rw(via->name.s, via->bsize); if(ptsd->cp + vlen + 2 >= ptsd->cbuf + TPS_DATA_SIZE) { LM_ERR("no more spage to pack via headers\n"); return -1; } if(i>1) { *ptsd->cp = ','; ptsd->cp++; if(i>2) { ptsd->x_via2.len++; } } memcpy(ptsd->cp, via->name.s, vlen); if(i==1) { ptsd->x_via1.s = ptsd->cp; ptsd->x_via1.len = vlen; if(via->branch!=NULL) { ptsd->x_vbranch1.s = ptsd->x_via1.s + (via->branch->value.s - via->name.s); ptsd->x_vbranch1.len = via->branch->value.len; } } else { if(i==2) { ptsd->x_via2.s = ptsd->cp; } ptsd->x_via2.len += vlen; } ptsd->cp += vlen; } } LM_DBG("compacted headers - x_via1: [%.*s](%d) - x_via2: [%.*s](%d)" " - x_vbranch1: [%.*s](%d)\n", ptsd->x_via1.len, ZSW(ptsd->x_via1.s), ptsd->x_via1.len, ptsd->x_via2.len, ZSW(ptsd->x_via2.s), ptsd->x_via2.len, ptsd->x_vbranch1.len, ZSW(ptsd->x_vbranch1.s), ptsd->x_vbranch1.len); i = 0; ptsd->a_rr.len = 0; for(hdr=msg->record_route; hdr; hdr=next_sibling_hdr(hdr)) { if (parse_rr(hdr) < 0) { LM_ERR("failed to parse RR\n"); return -1; } for(rr =(rr_t*)hdr->parsed; rr; rr=rr->next) { i++; if(ptsd->cp + rr->nameaddr.uri.len + 4 >= ptsd->cbuf + TPS_DATA_SIZE) { LM_ERR("no more spage to pack rr headers\n"); return -1; } if(i>1) { *ptsd->cp = ','; ptsd->cp++; ptsd->a_rr.len++; } *ptsd->cp = '<'; if(i==1) { ptsd->a_rr.s = ptsd->cp; } ptsd->cp++; ptsd->a_rr.len++; memcpy(ptsd->cp, rr->nameaddr.uri.s, rr->nameaddr.uri.len); if(i==1) { ptsd->bs_contact.s = ptsd->cp; ptsd->bs_contact.len = rr->nameaddr.uri.len; if(strnstr(ptsd->bs_contact.s, ";r2=on", ptsd->bs_contact.len)==NULL) { LM_DBG("single record routing by proxy\n"); ptsd->as_contact.s = ptsd->cp; ptsd->as_contact.len = rr->nameaddr.uri.len; } } else { if(i==2 && ptsd->as_contact.len==0) { LM_DBG("double record routing by proxy\n"); ptsd->as_contact.s = ptsd->cp; ptsd->as_contact.len = rr->nameaddr.uri.len; } } ptsd->a_rr.len += rr->nameaddr.uri.len; ptsd->cp += rr->nameaddr.uri.len; *ptsd->cp = '>'; ptsd->cp++; ptsd->a_rr.len++; } } LM_DBG("compacted headers - a_rr: [%.*s](%d) - b_rr: [%.*s](%d)\n", ptsd->a_rr.len, ZSW(ptsd->a_rr.s), ptsd->a_rr.len, ptsd->b_rr.len, ZSW(ptsd->b_rr.s), ptsd->b_rr.len); LM_DBG("compacted headers - as_contact: [%.*s](%d) - bs_contact: [%.*s](%d)\n", ptsd->as_contact.len, ZSW(ptsd->as_contact.s), ptsd->as_contact.len, ptsd->bs_contact.len, ZSW(ptsd->bs_contact.s), ptsd->bs_contact.len); return 0; }
/*! * get first RR header and print comma separated bodies in oroute * - order = 0 normal; order = 1 reverse * - nb_recs - input=skip number of rr; output=number of printed rrs */ int print_rr_body(struct hdr_field *iroute, str *oroute, int order, unsigned int * nb_recs) { rr_t *p; int n = 0, nr=0; int i = 0; int route_len; #define MAX_RR_HDRS 64 static str route[MAX_RR_HDRS]; char *cp, *start; if(iroute==NULL) return 0; route_len= 0; memset(route, 0, MAX_RR_HDRS*sizeof(str)); while (iroute!=NULL) { if (parse_rr(iroute) < 0) { LM_ERR("failed to parse RR\n"); goto error; } p =(rr_t*)iroute->parsed; while (p) { route[n].s = p->nameaddr.name.s; route[n].len = p->len; LM_DBG("current rr is %.*s\n", route[n].len, route[n].s); n++; if(n==MAX_RR_HDRS) { LM_ERR("too many RR\n"); goto error; } p = p->next; } iroute = next_sibling_hdr(iroute); } for(i=0;i<n;i++){ if(!nb_recs || (nb_recs && ( (!order&& (i>=*nb_recs)) || (order && (i<=(n-*nb_recs)) )) ) ) { route_len+= route[i].len; nr++; } } if(nb_recs) LM_DBG("skipping %i route records\n", *nb_recs); route_len += --nr; /* for commas */ oroute->s=(char*)pkg_malloc(route_len); if(oroute->s==0) { LM_ERR("no more pkg mem\n"); goto error; } cp = start = oroute->s; if(order==0) { i= (nb_recs == NULL) ? 0:*nb_recs; while (i<n) { memcpy(cp, route[i].s, route[i].len); cp += route[i].len; if (++i<n) *(cp++) = ','; } } else { i = (nb_recs == NULL) ? n-1 : (n-*nb_recs-1); while (i>=0) { memcpy(cp, route[i].s, route[i].len); cp += route[i].len; if (i-->0) *(cp++) = ','; } } oroute->len=cp - start; LM_DBG("out rr [%.*s]\n", oroute->len, oroute->s); LM_DBG("we have %i records\n", n); if(nb_recs != NULL) *nb_recs = (unsigned int)n; return 0; error: return -1; }
/* Build a local request based on a previous request; main * customers of this function are local ACK and local CANCEL */ char *build_local(struct cell *Trans,unsigned int branch, unsigned int *len, char *method, int method_len, str *to #ifdef CANCEL_REASON_SUPPORT , struct cancel_reason* reason #endif /* CANCEL_REASON_SUPPORT */ ) { char *cancel_buf, *p, *via; unsigned int via_len; struct hdr_field *hdr; char branch_buf[MAX_BRANCH_PARAM_LEN]; int branch_len; str branch_str; str via_id; struct hostport hp; #ifdef CANCEL_REASON_SUPPORT int reason_len, code_len; struct hdr_field *reas1, *reas_last; #endif /* CANCEL_REASON_SUPPORT */ /* init */ via_id.s=0; via_id.len=0; /* method, separators, version: "CANCEL sip:[email protected] SIP/2.0" */ *len=SIP_VERSION_LEN + method_len + 2 /* spaces */ + CRLF_LEN; *len+=Trans->uac[branch].uri.len; /*via*/ if (!t_calc_branch(Trans, branch, branch_buf, &branch_len )) goto error; branch_str.s=branch_buf; branch_str.len=branch_len; set_hostport(&hp, (is_local(Trans))?0:(Trans->uas.request)); #ifdef USE_TCP if (!is_local(Trans) && ((Trans->uas.request->rcv.proto==PROTO_TCP) #ifdef USE_TLS || (Trans->uas.request->rcv.proto==PROTO_TLS) #endif /* USE_TLS */ )){ if ((via_id.s=id_builder(Trans->uas.request, (unsigned int*)&via_id.len))==0){ LM_ERR("id builder failed\n"); /* try to continue without id */ } } #endif /* USE_TCP */ via=via_builder(&via_len, NULL, &Trans->uac[branch].request.dst, &branch_str, via_id.s?&via_id:0 , &hp ); /* via_id.s not needed anylonger => free it */ if (via_id.s) { pkg_free(via_id.s); via_id.s=0; via_id.len=0; } if (!via) { LM_ERR("no via header got from builder\n"); goto error; } *len+= via_len; /*headers*/ *len+=Trans->from.len+Trans->callid.len+to->len+ +Trans->cseq_n.len+1+method_len+CRLF_LEN+MAXFWD_HEADER_LEN; /* copy'n'paste Route headers */ if (!is_local(Trans)) { for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next ) if (hdr->type==HDR_ROUTE_T) *len+=hdr->len; } /* User Agent */ if (server_signature) { *len += user_agent_hdr.len + CRLF_LEN; } /* Content Length, EoM */ *len+=CONTENT_LENGTH_LEN+1 + CRLF_LEN; #ifdef CANCEL_REASON_SUPPORT reason_len = 0; reas1 = 0; reas_last = 0; /* compute reason size (if no reason or disabled => reason_len == 0)*/ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0 && cfg_get(tm, tm_cfg, local_cancel_reason))){ /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */ reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN + (reason->u.text.s? REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) + CRLF_LEN; } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS && !(Trans->flags & T_NO_E2E_CANCEL_REASON))) { reason_len = reason->u.packed_hdrs.len; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel && !(Trans->flags & T_NO_E2E_CANCEL_REASON)) { /* parse the entire cancel, to get all the Reason headers */ if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) { LM_WARN("failed to parse headers\n"); } for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ reason_len += hdr->len; reas_last=hdr; } } else if (unlikely(reason->cause < CANCEL_REAS_MIN)) LM_BUG("unhandled reason cause %d\n", reason->cause); } *len+= reason_len; #endif /* CANCEL_REASON_SUPPORT */ *len+= CRLF_LEN; /* end of msg. */ cancel_buf=shm_malloc( *len+1 ); if (!cancel_buf) { LM_ERR("cannot allocate memory\n"); goto error01; } p = cancel_buf; append_str( p, method, method_len ); append_str( p, " ", 1 ); append_str( p, Trans->uac[branch].uri.s, Trans->uac[branch].uri.len); append_str( p, " " SIP_VERSION CRLF, 1+SIP_VERSION_LEN+CRLF_LEN ); /* insert our via */ append_str(p,via,via_len); /*other headers*/ append_str( p, Trans->from.s, Trans->from.len ); append_str( p, Trans->callid.s, Trans->callid.len ); append_str( p, to->s, to->len ); append_str( p, Trans->cseq_n.s, Trans->cseq_n.len ); append_str( p, " ", 1 ); append_str( p, method, method_len ); append_str( p, CRLF, CRLF_LEN ); append_str( p, MAXFWD_HEADER, MAXFWD_HEADER_LEN ); if (!is_local(Trans)) { for ( hdr=Trans->uas.request->headers ; hdr ; hdr=hdr->next ) if(hdr->type==HDR_ROUTE_T) { append_str(p, hdr->name.s, hdr->len ); } } /* User Agent header */ if (server_signature) { append_str(p, user_agent_hdr.s, user_agent_hdr.len ); append_str(p, CRLF, CRLF_LEN ); } /* Content Length */ append_str(p, CONTENT_LENGTH "0" CRLF, CONTENT_LENGTH_LEN + 1 + CRLF_LEN); #ifdef CANCEL_REASON_SUPPORT /* add reason if needed */ if (reason_len) { if (likely(reason->cause > 0)) { append_str(p, REASON_PREFIX, REASON_PREFIX_LEN); code_len=ushort2sbuf(reason->cause, p, *len-(int)(p-cancel_buf)); if (unlikely(code_len==0)) LM_BUG("not enough space to write reason code"); p+=code_len; if (reason->u.text.s){ append_str(p, REASON_TEXT, REASON_TEXT_LEN); *p='"'; p++; append_str(p, reason->u.text.s, reason->u.text.len); *p='"'; p++; } append_str(p, CRLF, CRLF_LEN); } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) { append_str(p, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ append_str(p, hdr->name.s, hdr->len); if (likely(hdr==reas_last)) break; } } } #endif /* CANCEL_REASON_SUPPORT */ append_str(p, CRLF, CRLF_LEN); /* msg. end */ *p=0; pkg_free(via); return cancel_buf; error01: pkg_free(via); error: return NULL; }
/* Re-parsing version of build_local() function: * it builds a local CANCEL or ACK (for non-200 response) request based on * the previous INVITE which was sent out. * * Can not be used to build other type of requests! */ char *build_local_reparse(struct cell *Trans,unsigned int branch, unsigned int *len, char *method, int method_len, str *to #ifdef CANCEL_REASON_SUPPORT , struct cancel_reason *reason #endif /* CANCEL_REASON_SUPPORT */ ) { char *invite_buf, *invite_buf_end; char *cancel_buf; char *s, *s1, *d; /* source and destination buffers */ short invite_len; enum _hdr_types_t hf_type; int first_via, to_len; int cancel_buf_len; #ifdef CANCEL_REASON_SUPPORT int reason_len, code_len; struct hdr_field *reas1, *reas_last, *hdr; #endif /* CANCEL_REASON_SUPPORT */ int hadded = 0; sr_cfgenv_t *cenv = NULL; invite_buf = Trans->uac[branch].request.buffer; invite_len = Trans->uac[branch].request.buffer_len; if (!invite_buf || !invite_len) { LM_ERR("INVITE is missing\n"); goto error; } if ((*invite_buf != 'I') && (*invite_buf != 'i')) { LM_ERR("trying to build with local reparse" " for a non-INVITE request?\n"); goto error; } #ifdef CANCEL_REASON_SUPPORT reason_len = 0; reas1 = 0; reas_last = 0; /* compute reason size (if no reason or disabled => reason_len == 0)*/ if (reason && reason->cause != CANCEL_REAS_UNKNOWN){ if (likely(reason->cause > 0 && cfg_get(tm, tm_cfg, local_cancel_reason))){ /* Reason: SIP;cause=<reason->cause>[;text=<reason->u.text.s>] */ reason_len = REASON_PREFIX_LEN + USHORT2SBUF_MAX_LEN + (reason->u.text.s? REASON_TEXT_LEN + 1 + reason->u.text.len + 1 : 0) + CRLF_LEN; } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS && !(Trans->flags & T_NO_E2E_CANCEL_REASON))) { reason_len = reason->u.packed_hdrs.len; } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL && reason->u.e2e_cancel && !(Trans->flags & T_NO_E2E_CANCEL_REASON)) { /* parse the entire cancel, to get all the Reason headers */ if(parse_headers(reason->u.e2e_cancel, HDR_EOH_F, 0)<0) { LM_WARN("failed to parse headers\n"); } for(hdr=get_hdr(reason->u.e2e_cancel, HDR_REASON_T), reas1=hdr; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ reason_len += hdr->len; reas_last=hdr; } } else if (unlikely(reason->cause < CANCEL_REAS_MIN)) LM_BUG("unhandled reason cause %d\n", reason->cause); } #endif /* CANCEL_REASON_SUPPORT */ invite_buf_end = invite_buf + invite_len; s = invite_buf; /* Allocate memory for the new message. The new request will be smaller than the INVITE, so the same size is enough. I just extend it with the length of new To HF to be sure. Ugly, but we avoid lots of checks and memory allocations this way */ to_len = to ? to->len : 0; #ifdef CANCEL_REASON_SUPPORT cancel_buf_len = invite_len + to_len + reason_len; #else cancel_buf_len = invite_len + to_len; #endif /* CANCEL_REASON_SUPPORT */ cancel_buf = shm_malloc(sizeof(char)*cancel_buf_len); if (!cancel_buf) { LM_ERR("cannot allocate shared memory\n"); goto error; } d = cancel_buf; /* method name + space */ append_str(d, method, method_len); *d = ' '; d++; /* skip "INVITE " and copy the rest of the line including CRLF */ s += 7; s1 = s; s = eat_line(s, invite_buf_end - s); append_str(d, s1, s - s1); cenv = sr_cfgenv_get(); /* check every header field name, we must exclude and modify some of the headers */ first_via = 1; while (s < invite_buf_end) { s1 = s; if ((*s == '\n') || (*s == '\r')) { /* end of SIP msg */ hf_type = HDR_EOH_T; } else { /* parse HF name */ s = lw_get_hf_name(s, invite_buf_end, &hf_type); } switch(hf_type) { case HDR_CSEQ_T: /* find the method name and replace it */ while ((s < invite_buf_end) && ((*s == ':') || (*s == ' ') || (*s == '\t') || ((*s >= '0') && (*s <= '9'))) ) s++; append_str(d, s1, s - s1); append_str(d, method, method_len); append_str(d, CRLF, CRLF_LEN); s = lw_next_line(s, invite_buf_end); break; case HDR_VIA_T: s = lw_next_line(s, invite_buf_end); if (first_via) { /* copy hf */ append_str(d, s1, s - s1); first_via = 0; } /* else skip this line, we need olny the first via */ break; case HDR_TO_T: if (to_len == 0) { /* there is no To tag required, just copy paste * the header */ s = lw_next_line(s, invite_buf_end); append_str(d, s1, s - s1); } else { /* use the given To HF instead of the original one */ append_str(d, to->s, to->len); /* move the pointer to the next line */ s = lw_next_line(s, invite_buf_end); } break; case HDR_FROM_T: case HDR_CALLID_T: case HDR_ROUTE_T: case HDR_MAXFORWARDS_T: /* copy hf */ s = lw_next_line(s, invite_buf_end); append_str(d, s1, s - s1); break; case HDR_REQUIRE_T: case HDR_PROXYREQUIRE_T: /* skip this line */ s = lw_next_line(s, invite_buf_end); break; case HDR_CONTENTLENGTH_T: /* copy hf name with 0 value */ append_str(d, s1, s - s1); append_str(d, ": 0" CRLF, 3 + CRLF_LEN); /* move the pointer to the next line */ s = lw_next_line(s, invite_buf_end); break; case HDR_EOH_T: /* end of SIP message found */ #ifdef CANCEL_REASON_SUPPORT /* add reason if needed */ if (reason_len) { /* if reason_len !=0, no need for any reason enabled * checks */ if (likely(reason->cause > 0)) { append_str(d, REASON_PREFIX, REASON_PREFIX_LEN); code_len=ushort2sbuf(reason->cause, d, cancel_buf_len-(int)(d-cancel_buf)); if (unlikely(code_len==0)) LM_BUG("not enough space to write reason code"); d+=code_len; if (reason->u.text.s){ append_str(d, REASON_TEXT, REASON_TEXT_LEN); *d='"'; d++; append_str(d, reason->u.text.s, reason->u.text.len); *d='"'; d++; } append_str(d, CRLF, CRLF_LEN); } else if (likely(reason->cause == CANCEL_REAS_PACKED_HDRS)) { append_str(d, reason->u.packed_hdrs.s, reason->u.packed_hdrs.len); } else if (reason->cause == CANCEL_REAS_RCVD_CANCEL) { for(hdr=reas1; hdr; hdr=next_sibling_hdr(hdr)) { /* hdr->len includes CRLF */ append_str(d, hdr->name.s, hdr->len); if (likely(hdr==reas_last)) break; } } } #endif /* CANCEL_REASON_SUPPORT */ /* final (end-of-headers) CRLF */ append_str(d, CRLF, CRLF_LEN); *len = d - cancel_buf; /* LOG(L_DBG, "DBG: build_local: %.*s\n", *len, cancel_buf); */ return cancel_buf; default: s = lw_next_line(s, invite_buf_end); hadded = 0; /* uac auth headers */ if(Trans->uas.request && (Trans->uas.request->msg_flags & FL_UAC_AUTH)) { if(s1 + cenv->uac_cseq_auth.len + 2 < invite_buf_end) { if(s1[cenv->uac_cseq_auth.len]==':' && strncmp(s1, cenv->uac_cseq_auth.s, cenv->uac_cseq_auth.len)==0) { hadded = 1; append_str(d, s1, s - s1); } else if(s1[cenv->uac_cseq_refresh.len]==':' && strncmp(s1, cenv->uac_cseq_refresh.s, cenv->uac_cseq_refresh.len)==0) { hadded = 1; append_str(d, s1, s - s1); } } } if(likely(hadded==0)) { if (cfg_get(tm, tm_cfg, ac_extra_hdrs).len && (s1 + cfg_get(tm, tm_cfg, ac_extra_hdrs).len < invite_buf_end) && (strncasecmp(s1, cfg_get(tm, tm_cfg, ac_extra_hdrs).s, cfg_get(tm, tm_cfg, ac_extra_hdrs).len) == 0)) { append_str(d, s1, s - s1); } } break; } } /* HDR_EOH_T was not found in the buffer, the message is corrupt */ LM_ERR("HDR_EOH_T was not found\n"); shm_free(cancel_buf); error: LM_ERR("cannot build %.*s request\n", method_len, method); return NULL; }
int th_flip_record_route(sip_msg_t *msg, int mode) { hdr_field_t *hdr; struct lump* l; int i; rr_t *rr; str out; int utype; str pval; int r2; int act; if(msg->record_route==NULL) { LM_DBG("no record route header\n"); return 0; } hdr = msg->record_route; i = 0; act = 0; if(mode==1) act = 2; while(hdr!=NULL) { if (parse_rr(hdr) < 0) { LM_ERR("failed to parse RR\n"); return -1; } rr =(rr_t*)hdr->parsed; while(rr) { i++; r2 = 0; utype = th_get_uri_type(&rr->nameaddr.uri, &r2, &pval); if(utype==0 && mode==1) { if(r2==1) { act--; if(act==0) return 0; utype = 1; } else { return 0; } } out.s = NULL; switch(utype) { case 1: /* encode */ if(act!=0 && mode==1) { out.s = th_mask_encode(rr->nameaddr.uri.s, rr->nameaddr.uri.len, &th_uri_prefix, &out.len); if(out.s==NULL) { LM_ERR("cannot encode r-r %d\n", i); return -1; } } break; case 2: /* decode */ if(mode==0) { out.s = th_mask_decode(pval.s, pval.len, &th_uparam_prefix, 0, &out.len); if(out.s==NULL) { LM_ERR("cannot decode r-r %d\n", i); return -1; } } break; } if(out.s!=NULL) { l=del_lump(msg, rr->nameaddr.uri.s-msg->buf, rr->nameaddr.uri.len, 0); if (l==0) { LM_ERR("failed deleting r-r [%d]\n", i); pkg_free(out.s); return -1; } if (insert_new_lump_after(l, out.s, out.len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(out.s); return -1; } } rr = rr->next; } hdr = next_sibling_hdr(hdr); } return 0; }
int th_unmask_via(sip_msg_t *msg, str *cookie) { hdr_field_t *hdr; struct via_body *via; struct via_body *via2; struct via_param *vp; struct lump* l; int i; str out; int vlen; i=0; for(hdr=msg->h_via1; hdr; hdr=next_sibling_hdr(hdr)) { for(via=(struct via_body*)hdr->parsed; via; via=via->next) { i++; LM_DBG("=======via[%d]\n", i); LM_DBG("hdr: [%.*s]\n", via->hdr.len, via->hdr.s); vlen = th_skip_rw(via->name.s, via->bsize); LM_DBG("body: %d: [%.*s]\n", vlen, vlen, via->name.s); if(i!=1) { vp = th_get_via_param(via, &th_vparam_name); if(vp==NULL) { LM_ERR("cannot find param in via %d\n", i); return -1; } if(i==2) out.s = th_mask_decode(vp->value.s, vp->value.len, &th_vparam_prefix, CRLF_LEN+1, &out.len); else out.s = th_mask_decode(vp->value.s, vp->value.len, &th_vparam_prefix, 0, &out.len); if(out.s==NULL) { LM_ERR("cannot encode via %d\n", i); return -1; } LM_DBG("+body: %d: [%.*s]\n", out.len, out.len, out.s); if(i==2) { via2=pkg_malloc(sizeof(struct via_body)); if (via2==0) { LM_ERR("out of memory\n"); pkg_free(out.s); return -1; } memset(via2, 0, sizeof(struct via_body)); memcpy(out.s+out.len, CRLF, CRLF_LEN); out.s[out.len+CRLF_LEN]='X'; if(parse_via(out.s, out.s+out.len+CRLF_LEN+1, via2)==NULL) { LM_ERR("error parsing decoded via2\n"); free_via_list(via2); pkg_free(out.s); return -1; } out.s[out.len] = '\0'; vp = th_get_via_param(via2, &th_cookie_name); if(vp==NULL) { LM_ERR("cannot find cookie in via2\n"); free_via_list(via2); pkg_free(out.s); return -1; } *cookie = vp->value; free_via_list(via2); } l=del_lump(msg, via->name.s-msg->buf, vlen, 0); if (l==0) { LM_ERR("failed deleting via [%d]\n", i); pkg_free(out.s); return -1; } if (insert_new_lump_after(l, out.s, out.len, 0)==0) { LM_ERR("could not insert new lump\n"); pkg_free(out.s); return -1; } } } } return 0; }
/* * Find credentials with given realm in a SIP message header */ int find_credentials(struct sip_msg* msg, str* realm, hdr_types_t hftype, struct hdr_field** hdr) { struct hdr_field** hook, *ptr; hdr_flags_t hdr_flags; int res; str* r; /* * Determine if we should use WWW-Authorization or * Proxy-Authorization header fields, this parameter * is set in www_authorize and proxy_authorize */ switch(hftype) { case HDR_AUTHORIZATION_T: hook = &(msg->authorization); hdr_flags=HDR_AUTHORIZATION_F; break; case HDR_PROXYAUTH_T: hook = &(msg->proxy_auth); hdr_flags=HDR_PROXYAUTH_F; break; default: hook = &(msg->authorization); hdr_flags=HDR_T2F(hftype); break; } /* * If the credentials haven't been parsed yet, do it now */ if (*hook == 0) { /* No credentials parsed yet */ if (parse_headers(msg, hdr_flags, 0) == -1) { LM_ERR("error while parsing headers\n"); return -1; } } ptr = *hook; /* * Iterate through the credentials in the message and * find credentials with given realm */ while(ptr) { res = parse_credentials(ptr); if (res < 0) { LM_ERR("error while parsing credentials\n"); return (res == -1) ? -2 : -3; } else if (res == 0) { r = &(((auth_body_t*)(ptr->parsed))->digest.realm); if (r->len == realm->len) { if (!strncasecmp(realm->s, r->s, r->len)) { *hdr = ptr; return 0; } } } if (parse_headers(msg, hdr_flags, 1) == -1) { LM_ERR("error while parsing headers\n"); return -4; } else { ptr = next_sibling_hdr(ptr); if (!ptr) break; } } /* * Credentials with given realm not found */ return 1; }
int th_unmask_route(sip_msg_t *msg) { hdr_field_t *hdr; struct lump* l; int i; rr_t *rr; str out; str eval; if(msg->route==NULL) { LM_DBG("no record route header\n"); return 0; } hdr = msg->route; i = 0; while(hdr!=NULL) { if (parse_rr(hdr) < 0) { LM_ERR("failed to parse RR\n"); return -1; } rr =(rr_t*)hdr->parsed; while(rr) { i++; if(i!=1) { /* Skip if route is not encoded */ if (th_uri_prefix_checks && ((rr->nameaddr.uri.len<th_uri_prefix.len) || (strncasecmp(rr->nameaddr.uri.s,th_uri_prefix.s, th_uri_prefix.len)!=0))) { LM_DBG("rr %d is not encoded: [%.*s] - missing prefix\n", i, rr->nameaddr.uri.len, rr->nameaddr.uri.s); rr = rr->next; continue; } if(th_get_uri_param_value(&rr->nameaddr.uri, &th_uparam_name, &eval)<0 || eval.len<=0) { LM_DBG("rr %d is not encoded: [%.*s] - missing param\n", i, rr->nameaddr.uri.len, rr->nameaddr.uri.s); rr = rr->next; continue; } out.s = th_mask_decode(eval.s, eval.len, &th_uparam_prefix, 0, &out.len); if(out.s==NULL) { LM_ERR("cannot decode R %d\n", i); return -1; } l=del_lump(msg, rr->nameaddr.uri.s-msg->buf, rr->nameaddr.uri.len, 0); if (l==0) { LM_ERR("failed deleting R [%d]\n", i); pkg_free(out.s); return -1; } if (insert_new_lump_after(l, out.s, out.len, 0)==0){ LM_ERR("could not insert new lump\n"); pkg_free(out.s); return -1; } } rr = rr->next; } hdr = next_sibling_hdr(hdr); } return 0; }
/*! \brief * Combines all Path HF bodies into one string. */ int build_path_vector(struct sip_msg *_m, str *path, str *received) { static char buf[MAX_PATH_SIZE]; static char uri_buf[MAX_URI_SIZE]; static str uri_str; char *p; struct hdr_field *hdr; struct sip_uri puri; rr_t *route = 0; path->len = 0; path->s = 0; received->s = 0; received->len = 0; if(parse_headers(_m, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse the message\n"); goto error; } for( hdr=_m->path,p=buf ; hdr ; hdr = next_sibling_hdr(hdr)) { /* check for max. Path length */ if( p-buf+hdr->body.len+1 >= MAX_PATH_SIZE) { LM_ERR("Overall Path body exceeds max. length of %d\n", MAX_PATH_SIZE); goto error; } if(p!=buf) *(p++) = ','; memcpy( p, hdr->body.s, hdr->body.len); p += hdr->body.len; } if (p!=buf) { /* check if next hop is a loose router */ if (parse_rr_body( buf, p-buf, &route) < 0) { LM_ERR("failed to parse Path body, no head found\n"); goto error; } if (parse_uri(route->nameaddr.uri.s,route->nameaddr.uri.len,&puri)<0){ LM_ERR("failed to parse the first Path URI\n"); goto error; } if (!puri.lr.s) { LM_ERR("first Path URI is not a loose-router, not supported\n"); goto error; } if (path_use_params) { param_hooks_t hooks; param_t *params; if (parse_params(&(puri.params),CLASS_CONTACT,&hooks,¶ms)!=0){ LM_ERR("failed to parse parameters of first hop\n"); goto error; } /* Not interested in param body - just the hooks */ free_params(params); if (hooks.contact.received) { uri_str.s = uri_buf; uri_str.len = MAX_URI_SIZE; if (unescape_user(&(hooks.contact.received->body), &uri_str) < 0) { LM_ERR("unescaping received failed\n"); goto error; } *received = uri_str; LM_DBG("received is <%.*s>\n", received->len, received->s); } } free_rr(&route); } path->s = buf; path->len = p-buf; LM_DBG("path is <%.*s>\n", path->len, path->s); return 0; error: if(route) free_rr(&route); return -1; }