int init_rb( struct retr_buf *rb, struct sip_msg *msg) { struct socket_info* send_sock; struct via_body* via; int proto; via=msg->via1; if (!reply_to_via) { update_sock_struct_from_ip( &rb->dst.to, msg ); proto=msg->rcv.proto; } else { /*init retrans buffer*/ if (update_sock_struct_from_via( &(rb->dst.to), msg, via )==-1) { LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst: %.*s\n", via->host.len, via->host.s ); ser_error=E_BAD_VIA; return 0; } proto=via->proto; } rb->dst.proto=proto; rb->dst.proto_reserved1=msg->rcv.proto_reserved1; send_sock=get_send_socket(&rb->dst.to, proto); if (send_sock==0) { LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d " "no socket\n", rb->dst.to.s.sa_family, proto); ser_error=E_BAD_VIA; return 0; } rb->dst.send_sock=send_sock; return 1; }
int init_rb( struct retr_buf *rb, struct sip_msg *msg) { /*struct socket_info* send_sock;*/ struct via_body* via; int proto; int backup_mhomed; /* rb. timers are init. init_t()/new_cell() */ via=msg->via1; /* rb->dst is already init (0) by new_t()/build_cell() */ if (!reply_to_via) { update_sock_struct_from_ip( &rb->dst.to, msg ); proto=msg->rcv.proto; } else { /*init retrans buffer*/ if (update_sock_struct_from_via( &(rb->dst.to), msg, via )==-1) { LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst: %.*s\n", via->host.len, via->host.s ); ser_error=E_BAD_VIA; return 0; } proto=via->proto; } rb->dst.proto=proto; rb->dst.id=msg->rcv.proto_reserved1; #ifdef USE_COMP rb->dst.comp=via->comp_no; #endif /* turn off mhomed for generating replies -- they are ideally sent to where request came from to make life with NATs and other beasts easier */ backup_mhomed=mhomed; mhomed=0; mhomed=backup_mhomed; /* use for sending replies the incoming interface of the request -bogdan */ /*send_sock=get_send_socket(msg, &rb->dst.to, proto); if (send_sock==0) { LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d " "no socket\n", rb->dst.to.s.sa_family, proto); ser_error=E_BAD_VIA; return 0; }*/ rb->dst.send_sock=msg->rcv.bind_address; return 1; }
/* removes first via & sends msg to the second */ int forward_reply(struct sip_msg* msg) { char* new_buf; struct dest_info dst; unsigned int new_len; int r; #ifdef USE_TCP char* s; int len; #endif init_dest_info(&dst); new_buf=0; /*check if first via host = us */ if (check_via){ if (check_self(&msg->via1->host, msg->via1->port?msg->via1->port:SIP_PORT, msg->via1->proto)!=1){ LOG(L_NOTICE, "ERROR: forward_reply: host in first via!=me :" " %.*s:%d\n", msg->via1->host.len, msg->via1->host.s, msg->via1->port); /* send error msg back? */ goto error; } } /* check modules response_f functions */ for (r=0; r<mod_response_cbk_no; r++) if (mod_response_cbks[r](msg)==0) goto skip; /* we have to forward the reply stateless, so we need second via -bogdan*/ if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* no second via => error */ LOG(L_DBG, "reply cannot be forwarded - no 2nd via\n"); goto error; } new_buf = build_res_buf_from_sip_res( msg, &new_len); if (!new_buf){ LOG(L_ERR, "ERROR: forward_reply: building failed\n"); goto error; } dst.proto=msg->via2->proto; SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags); if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error; #ifdef USE_COMP dst.comp=msg->via2->comp_no; #endif #if defined USE_TCP || defined USE_SCTP if ( #ifdef USE_TCP dst.proto==PROTO_TCP || dst.proto==PROTO_WS #ifdef USE_TLS || dst.proto==PROTO_TLS || dst.proto==PROTO_WSS #endif #ifdef USE_SCTP || #endif /* USE_SCTP */ #endif /* USE_TCP */ #ifdef USE_SCTP dst.proto==PROTO_SCTP #endif /* USE_SCTP */ ){ /* find id in i param if it exists */ if (msg->via1->i && msg->via1->i->value.s){ s=msg->via1->i->value.s; len=msg->via1->i->value.len; DBG("forward_reply: i=%.*s\n",len, ZSW(s)); if (reverse_hex2int(s, len, (unsigned int*)&dst.id)<0){ LOG(L_ERR, "ERROR: forward_reply: bad via i param \"%.*s\"\n", len, ZSW(s)); dst.id=0; } } } #endif apply_force_send_socket(&dst, msg); if (msg_send(&dst, new_buf, new_len)<0) { STATS_RPL_FWD_DROP(); goto error; } #ifdef STATS STATS_TX_RESPONSE( (msg->first_line.u.reply.statuscode/100) ); #endif DBG(" reply forwarded to %.*s:%d\n", msg->via2->host.len, msg->via2->host.s, (unsigned short) msg->via2->port); STATS_RPL_FWD_OK(); pkg_free(new_buf); skip: return 0; error: if (new_buf) pkg_free(new_buf); return -1; }
/*! \brief removes first via & sends msg to the second */ int forward_reply(struct sip_msg* msg) { char* new_buf; union sockaddr_union* to; unsigned int new_len; struct sr_module *mod; int proto; int id; /* used only by tcp*/ struct socket_info *send_sock; #ifdef USE_TCP char* s; int len; #endif to=0; id=0; new_buf=0; /*check if first via host = us */ if (check_via){ if (check_self(&msg->via1->host, msg->via1->port?msg->via1->port:SIP_PORT, msg->via1->proto)!=1){ LM_ERR("host in first via!=me : %.*s:%d\n", msg->via1->host.len, msg->via1->host.s, msg->via1->port); /* send error msg back? */ goto error; } } /* quick hack, slower for multiple modules*/ for (mod=modules;mod;mod=mod->next){ if ((mod->exports) && (mod->exports->response_f)){ LM_DBG("found module %s, passing reply to it\n", mod->exports->name); if (mod->exports->response_f(msg)==0) goto skip; } } /* if stateless fwd was disabled, we cannot have stateless replies here*/ if (sl_fwd_disabled) goto skip; /* we have to forward the reply stateless, so we need second via -bogdan*/ if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* no second via => error */ LM_ERR("no 2nd via found in reply\n"); goto error; } to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); if (to==0){ LM_ERR("out of pkg memory\n"); goto error; } new_buf = build_res_buf_from_sip_res( msg, &new_len); if (!new_buf){ LM_ERR("failed to build rpl from req failed\n"); goto error; } proto=msg->via2->proto; if (update_sock_struct_from_via( to, msg, msg->via2 )==-1) goto error; #ifdef USE_TCP if (proto==PROTO_TCP #ifdef USE_TLS || proto==PROTO_TLS #endif ){ /* find id in i param if it exists */ if (msg->via1->i&&msg->via1->i->value.s){ s=msg->via1->i->value.s; len=msg->via1->i->value.len; id=reverse_hex2int(s, len); } } #endif send_sock = get_send_socket(msg, to, proto); if (msg_send(send_sock, proto, to, id, new_buf, new_len)<0) { update_stat( drp_rpls, 1); goto error0; } update_stat( fwd_rpls, 1); /* * If no port is specified in the second via, then this * message output a wrong port number - zero. Despite that * the correct port is choosen in update_sock_struct_from_via, * as its visible with su_getport(to); . */ LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, msg->via2->host.s, (unsigned short) msg->via2->port); pkg_free(new_buf); pkg_free(to); skip: return 0; error: update_stat( err_rpls, 1); error0: if (new_buf) pkg_free(new_buf); if (to) pkg_free(to); return -1; }
/** removes first via & sends msg to the second * - mode param controls if modules sip response callbacks are executed */ static int do_forward_reply(struct sip_msg* msg, int mode) { char* new_buf; struct dest_info dst; unsigned int new_len; int r; struct ip_addr ip; #ifdef USE_TCP char* s; int len; #endif init_dest_info(&dst); new_buf=0; /*check if first via host = us */ if (check_via){ if (check_self(&msg->via1->host, msg->via1->port?msg->via1->port:SIP_PORT, msg->via1->proto)!=1){ LM_ERR("host in first via!=me : %.*s:%d\n", msg->via1->host.len, msg->via1->host.s, msg->via1->port); /* send error msg back? */ goto error; } } /* check modules response_f functions */ if(likely(mode==0)) { for (r=0; r<mod_response_cbk_no; r++) if (mod_response_cbks[r](msg)==0) goto skip; } /* we have to forward the reply stateless, so we need second via -bogdan*/ if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) { /* no second via => error */ LM_DBG("reply cannot be forwarded - no 2nd via\n"); goto error; } new_buf = build_res_buf_from_sip_res( msg, &new_len); if (!new_buf){ LM_ERR("building failed\n"); goto error; } dst.proto=msg->via2->proto; SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags); if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error; #ifdef USE_COMP dst.comp=msg->via2->comp_no; #endif #if defined USE_TCP || defined USE_SCTP if ( #ifdef USE_TCP dst.proto==PROTO_TCP || dst.proto==PROTO_WS #ifdef USE_TLS || dst.proto==PROTO_TLS || dst.proto==PROTO_WSS #endif #ifdef USE_SCTP || #endif /* USE_SCTP */ #endif /* USE_TCP */ #ifdef USE_SCTP dst.proto==PROTO_SCTP #endif /* USE_SCTP */ ){ /* find id in i param if it exists */ if (msg->via1->i && msg->via1->i->value.s){ s=msg->via1->i->value.s; len=msg->via1->i->value.len; LM_DBG("i=%.*s\n",len, ZSW(s)); if (reverse_hex2int(s, len, (unsigned int*)&dst.id)<0){ LM_ERR("bad via i param \"%.*s\"\n", len, ZSW(s)); dst.id=0; } } } #endif apply_force_send_socket(&dst, msg); /* call onsend_route */ if(dst.send_sock == NULL) { dst.send_sock=get_send_socket(msg, &dst.to, dst.proto); if (dst.send_sock==0){ LM_ERR("cannot forward reply\n"); goto done; } } if (onsend_route_enabled(SIP_REPLY)){ if (run_onsend(msg, &dst, new_buf, new_len)==0){ su2ip_addr(&ip, &(dst.to)); LM_ERR("reply to %s:%d(%d) dropped (onsend_route)\n", ip_addr2a(&ip), su_getport(&(dst.to)), dst.proto); goto error; /* error ? */ } } if (msg_send(&dst, new_buf, new_len)<0) { STATS_RPL_FWD_DROP(); goto error; } done: #ifdef STATS STATS_TX_RESPONSE( (msg->first_line.u.reply.statuscode/100) ); #endif LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, msg->via2->host.s, (unsigned short) msg->via2->port); STATS_RPL_FWD_OK(); pkg_free(new_buf); skip: return 0; error: if (new_buf) pkg_free(new_buf); return -1; }
int sl_send_reply(struct sip_msg *msg , int code, char* reason) { char *buf, *dset; unsigned int len; struct dest_info dst; struct bookmark dummy_bm; int backup_mhomed, ret, dset_len; if ( msg->first_line.u.request.method_value==METHOD_ACK) { LOG(L_WARN, "Warning: sl_send_reply: I won't send a reply for ACK!!\n"); goto error; } init_dest_info(&dst); if (reply_to_via) { if (update_sock_struct_from_via( &dst.to, msg, msg->via1 )==-1) { LOG(L_ERR, "ERROR: sl_send_reply: " "cannot lookup reply dst: %s\n", msg->via1->host.s ); goto error; } } else update_sock_struct_from_ip( &dst.to, msg ); /* if that is a redirection message, dump current message set to it */ if (code>=300 && code<400) { dset=print_dset(msg, &dset_len); if (dset) { add_lump_rpl(msg, dset, dset_len, LUMP_RPL_HDR); } } /* add a to-tag if there is a To header field without it */ if ( /* since RFC3261, we append to-tags anywhere we can, except * 100 replies */ /* msg->first_line.u.request.method_value==METHOD_INVITE && */ code>=180 && (msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to)) && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) { calc_crc_suffix( msg, tag_suffix ); buf = build_res_buf_from_sip_req(code,reason,&sl_tag,msg,&len,&dummy_bm); } else { buf = build_res_buf_from_sip_req(code,reason,0,msg,&len,&dummy_bm); } if (!buf) { DBG("DEBUG: sl_send_reply: response building failed\n"); goto error; } /* supress multhoming support when sending a reply back -- that makes sure that replies will come from where requests came in; good for NATs (there is no known use for mhomed for locally generated replies; note: forwarded cross-interface replies do benefit of mhomed! */ backup_mhomed=mhomed; mhomed=0; /* use for sending the received interface -bogdan*/ dst.proto=msg->rcv.proto; dst.send_sock=msg->rcv.bind_address; dst.id=msg->rcv.proto_reserved1; #ifdef USE_COMP dst.comp=msg->via1->comp_no; #endif ret = msg_send(&dst, buf, len); mhomed=backup_mhomed; pkg_free(buf); if (ret<0) { goto error; } *(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME; update_sl_stats(code); return 1; error: update_sl_failures(); return -1; }
/*! * helper function for stateless reply */ int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag) { str buf = {0, 0}; str dset = {0, 0}; struct dest_info dst; struct bookmark dummy_bm; int backup_mhomed, ret; str text; int rt, backup_rt; struct run_act_ctx ctx; struct sip_msg pmsg; if (msg->first_line.u.request.method_value==METHOD_ACK) goto error; init_dest_info(&dst); if (reply_to_via) { if (update_sock_struct_from_via(&dst.to, msg, msg->via1 )==-1) { LOG(L_ERR, "ERROR: sl_reply_helper: cannot lookup reply dst: %s\n", msg->via1->host.s); goto error; } } else update_sock_struct_from_ip(&dst.to, msg); /* if that is a redirection message, dump current message set to it */ if (code>=300 && code<400) { dset.s=print_dset(msg, &dset.len); if (dset.s) { add_lump_rpl(msg, dset.s, dset.len, LUMP_RPL_HDR); } } text.s = reason; text.len = strlen(reason); /* add a to-tag if there is a To header field without it */ if ( /* since RFC3261, we append to-tags anywhere we can, except * 100 replies */ /* msg->first_line.u.request.method_value==METHOD_INVITE && */ code>=180 && (msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to)) && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) { if(tag!=NULL && tag->s!=NULL) { buf.s = build_res_buf_from_sip_req(code, &text, tag, msg, (unsigned int*)&buf.len, &dummy_bm); } else { calc_crc_suffix( msg, tag_suffix ); buf.s = build_res_buf_from_sip_req(code, &text, &sl_tag, msg, (unsigned int*)&buf.len, &dummy_bm); } } else { buf.s = build_res_buf_from_sip_req(code, &text, 0, msg, (unsigned int*)&buf.len, &dummy_bm); } if (!buf.s) { DBG("DEBUG: sl_reply_helper: response building failed\n"); goto error; } sl_run_callbacks(SLCB_REPLY_READY, msg, code, reason, &buf, &dst); /* supress multhoming support when sending a reply back -- that makes sure that replies will come from where requests came in; good for NATs (there is no known use for mhomed for locally generated replies; note: forwarded cross-interface replies do benefit of mhomed! */ backup_mhomed=mhomed; mhomed=0; /* use for sending the received interface -bogdan*/ dst.proto=msg->rcv.proto; dst.send_sock=msg->rcv.bind_address; dst.id=msg->rcv.proto_reserved1; #ifdef USE_COMP dst.comp=msg->via1->comp_no; #endif dst.send_flags=msg->rpl_send_flags; ret = msg_send(&dst, buf.s, buf.len); mhomed=backup_mhomed; rt = route_lookup(&event_rt, "sl:local-response"); if (unlikely(rt >= 0 && event_rt.rlist[rt] != NULL)) { if (likely(build_sip_msg_from_buf(&pmsg, buf.s, buf.len, inc_msg_no()) == 0)) { char *tmp = NULL; struct onsend_info onsnd_info; onsnd_info.to=&dst.to; onsnd_info.send_sock=dst.send_sock; onsnd_info.buf=buf.s; onsnd_info.len=buf.len; p_onsend=&onsnd_info; if (unlikely(!IS_SIP(msg))) { /* This is an HTTP reply... So fudge in a CSeq into the parsed message message structure so that $rm will work in the route */ struct hdr_field *hf; struct cseq_body *cseqb; char *tmp2; int len; if ((hf = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field))) == NULL) { LM_ERR("out of package memory\n"); goto event_route_error; } if ((cseqb = (struct cseq_body *) pkg_malloc(sizeof(struct cseq_body))) == NULL) { LM_ERR("out of package memory\n"); pkg_free(hf); goto event_route_error; } if ((tmp = (char *) pkg_malloc(sizeof(char) * (msg->first_line.u.request.method.len + 5))) == NULL) { LM_ERR("out of package memory\n"); pkg_free(cseqb); pkg_free(hf); goto event_route_error; } memset(hf, 0, sizeof(struct hdr_field)); memset(cseqb, 0, sizeof(struct cseq_body)); len = sprintf(tmp, "0 %.*s\r\n", msg->first_line.u.request.method.len, msg->first_line.u.request.method.s); tmp2 = parse_cseq(tmp, &tmp[len], cseqb); hf->type = HDR_CSEQ_T; hf->body.s = tmp; hf->body.len = tmp2 - tmp; hf->parsed = cseqb; pmsg.parsed_flag|=HDR_CSEQ_F; pmsg.cseq = hf; if (pmsg.last_header==0) { pmsg.headers=hf; pmsg.last_header=hf; } else { pmsg.last_header->next=hf; pmsg.last_header=hf; } } backup_rt = get_route_type(); set_route_type(LOCAL_ROUTE); init_run_actions_ctx(&ctx); run_top_route(event_rt.rlist[rt], &pmsg, 0); set_route_type(backup_rt); p_onsend=0; if (tmp != NULL) pkg_free(tmp); event_route_error: free_sip_msg(&pmsg); } } pkg_free(buf.s); if (ret<0) { goto error; } *(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME; update_sl_stats(code); return 1; error: update_sl_failures(); return -1; }