Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * Copyright (C) 2005-2009 Voice Sistem SRL |
4 | | * |
5 | | * This file is part of opensips, a free SIP server. |
6 | | * |
7 | | * opensips is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version |
11 | | * |
12 | | * opensips is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | * |
21 | | * History: |
22 | | * ------- |
23 | | * 2001-??-?? created by andrei |
24 | | * ????-??-?? lots of changes by a lot of people |
25 | | * 2003-01-23 support for determination of outbound interface added : |
26 | | * get_out_socket (jiri) |
27 | | * 2003-01-24 reply to rport support added, contributed by |
28 | | * Maxim Sobolev <sobomax@FreeBSD.org> and modified by andrei |
29 | | * 2003-02-11 removed calls to upd_send & tcp_send & replaced them with |
30 | | * calls to msg_send (andrei) |
31 | | * 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei) |
32 | | * 2003-04-02 fixed get_send_socket for tcp fwd to udp (andrei) |
33 | | * 2003-04-03 added su_setport (andrei) |
34 | | * 2003-04-04 update_sock_struct_from_via now differentiates between |
35 | | * local replies & "normal" replies (andrei) |
36 | | * 2003-04-12 update_sock_struct_from via uses also FL_FORCE_RPORT for |
37 | | * local replies (andrei) |
38 | | * 2003-08-21 check_self properly handles ipv6 addresses & refs (andrei) |
39 | | * 2003-10-21 check_self updated to handle proto (andrei) |
40 | | * 2003-10-24 converted to the new socket_info lists (andrei) |
41 | | * 2004-10-10 modified check_self to use grep_sock_info (andrei) |
42 | | * 2004-11-08 added force_send_socket support in get_send_socket (andrei) |
43 | | * 2006-09-06 added new algorithm for building VIA branch parameter for |
44 | | * stateless requests - it complies to RFC3261 requirement to be |
45 | | * unique through time and space (bogdan) |
46 | | */ |
47 | | |
48 | | /*! |
49 | | * \file |
50 | | * \brief OpenSIPS Stateless forward support |
51 | | */ |
52 | | |
53 | | |
54 | | #include <string.h> |
55 | | #include <stdio.h> |
56 | | #include <stdlib.h> |
57 | | #include <errno.h> |
58 | | #include <sys/types.h> |
59 | | #include <sys/socket.h> |
60 | | #include <netdb.h> |
61 | | #include <netinet/in.h> |
62 | | #include <arpa/inet.h> |
63 | | |
64 | | #include "forward.h" |
65 | | #include "parser/msg_parser.h" |
66 | | #include "parser/parse_from.h" |
67 | | #include "dprint.h" |
68 | | #include "ut.h" |
69 | | #include "dset.h" |
70 | | #include "mem/mem.h" |
71 | | #include "msg_translator.h" |
72 | | #include "sr_module.h" |
73 | | #include "ip_addr.h" |
74 | | #include "resolve.h" |
75 | | #include "net/trans.h" |
76 | | #include "name_alias.h" |
77 | | #include "socket_info.h" |
78 | | #include "core_stats.h" |
79 | | #include "blacklists.h" |
80 | | #include "msg_callbacks.h" |
81 | | #include "md5utils.h" |
82 | | |
83 | | |
84 | | |
85 | | /*! \brief return a socket_info_pointer to the sending socket |
86 | | * \note As opposed to |
87 | | * get_send_socket(), which returns process's default socket, get_out_socket |
88 | | * attempts to determine the outbound interface which will be used; |
89 | | * it creates a temporary connected socket to determine it; it will |
90 | | * be very likely noticeably slower, but it can deal better with |
91 | | * multihomed hosts |
92 | | */ |
93 | | const struct socket_info* get_out_socket(const union sockaddr_union* to, int proto) |
94 | 0 | { |
95 | 0 | int temp_sock; |
96 | 0 | socklen_t len; |
97 | 0 | union sockaddr_union from; |
98 | 0 | const struct socket_info* si; |
99 | 0 | struct ip_addr ip, ip_dst; |
100 | |
|
101 | 0 | if (proto!=PROTO_UDP) { |
102 | 0 | LM_CRIT("can only be called for UDP\n"); |
103 | 0 | return 0; |
104 | 0 | } |
105 | | |
106 | 0 | temp_sock=socket(to->s.sa_family, SOCK_DGRAM, 0 ); |
107 | 0 | if (temp_sock==-1) { |
108 | 0 | LM_ERR("socket() failed: %s\n", strerror(errno)); |
109 | 0 | return 0; |
110 | 0 | } |
111 | 0 | if (connect(temp_sock, &to->s, sockaddru_len(*to))==-1) { |
112 | 0 | LM_ERR("connect failed: %s\n", strerror(errno)); |
113 | 0 | goto error; |
114 | 0 | } |
115 | 0 | len=sizeof(from); |
116 | 0 | if (getsockname(temp_sock, &from.s, &len)==-1) { |
117 | 0 | LM_ERR("getsockname failed: %s\n", strerror(errno)); |
118 | 0 | goto error; |
119 | 0 | } |
120 | 0 | su2ip_addr(&ip, &from); |
121 | 0 | si=find_si(&ip, 0, proto); |
122 | 0 | if (si==0) { |
123 | 0 | LM_ERR("outbound IP %s not found as listener\n", ip_addr2a(&ip)); |
124 | 0 | goto error; |
125 | 0 | } |
126 | 0 | close(temp_sock); |
127 | 0 | LM_DBG("socket determined: %p\n", si ); |
128 | 0 | return si; |
129 | 0 | error: |
130 | 0 | su2ip_addr( &ip_dst, to); |
131 | 0 | LM_ERR("failed to find route to %s\n", ip_addr2a(&ip_dst)); |
132 | 0 | close(temp_sock); |
133 | 0 | return 0; |
134 | 0 | } |
135 | | |
136 | | |
137 | | |
138 | | /*! \brief returns a socket_info pointer to the sending socket or 0 on error |
139 | | * \param msg SIP message (can be null) |
140 | | * \param to destination socket_union pointer |
141 | | * \param proto protocol |
142 | | * |
143 | | * \note if msg!=null and msg->force_send_socket, the force_send_socket will be used |
144 | | */ |
145 | | const struct socket_info* get_send_socket(struct sip_msg *msg, |
146 | | const union sockaddr_union* to, int proto) |
147 | 0 | { |
148 | 0 | const struct socket_info* send_sock; |
149 | | |
150 | | /* check if send interface is not forced */ |
151 | 0 | if (msg && msg->force_send_socket){ |
152 | 0 | if (msg->force_send_socket->proto!=proto){ |
153 | 0 | LM_DBG("force_send_socket of different proto (%d)!\n", proto); |
154 | 0 | msg->force_send_socket=find_si(&(msg->force_send_socket->address), |
155 | 0 | msg->force_send_socket->port_no, |
156 | 0 | proto); |
157 | 0 | } |
158 | 0 | if (msg->force_send_socket && (msg->force_send_socket->socket!=-1)) |
159 | 0 | return msg->force_send_socket; |
160 | 0 | else{ |
161 | 0 | if (msg->force_send_socket && msg->force_send_socket->socket==-1) |
162 | 0 | LM_WARN("not listening on the requested socket, no fork mode?\n"); |
163 | 0 | else |
164 | 0 | LM_WARN("protocol/port mismatch\n"); |
165 | 0 | } |
166 | 0 | }; |
167 | |
|
168 | 0 | if (mhomed && proto==PROTO_UDP){ |
169 | 0 | send_sock=get_out_socket(to, proto); |
170 | 0 | if ((send_sock==0) || (send_sock->socket!=-1)) |
171 | 0 | return send_sock; /* found or error*/ |
172 | 0 | else if (send_sock->socket==-1){ |
173 | 0 | LM_WARN("not listening on the requested socket, no fork mode?\n"); |
174 | | /* continue: try to use some socket */ |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | 0 | send_sock=0; |
179 | | /* check if we need to change the socket (different address families - |
180 | | * eg: ipv4 -> ipv6 or ipv6 -> ipv4) */ |
181 | 0 | switch(proto){ |
182 | 0 | case PROTO_UDP: |
183 | 0 | if (msg && msg->rcv.bind_address && |
184 | 0 | msg->rcv.bind_address->address.af==to->s.sa_family && |
185 | 0 | msg->rcv.bind_address->proto==PROTO_UDP) { |
186 | 0 | send_sock = msg->rcv.bind_address; |
187 | 0 | break; |
188 | 0 | } |
189 | | /* default logic for all protos */ |
190 | 0 | default: |
191 | | /* we don't really know the sending address (we can find it out, |
192 | | * but we'll need also to see if we listen on it, and if yes on |
193 | | * which port -> too complicated*/ |
194 | 0 | send_sock = (to->s.sa_family==AF_INET) ? |
195 | 0 | protos[proto].sendipv4 : protos[proto].sendipv6; |
196 | 0 | } |
197 | 0 | return send_sock; |
198 | 0 | } |
199 | | |
200 | | |
201 | | |
202 | | /*! \brief checks if the proto: host:port is one of the address we listen on |
203 | | * |
204 | | * if port==0, the port number is ignored |
205 | | * if proto==0 (PROTO_NONE) the protocol is ignored |
206 | | * returns 1 if true, 0 if false, -1 on error |
207 | | * WARNING: uses str2ip6 so it will overwrite any previous |
208 | | * unsaved result of this function (static buffer) |
209 | | */ |
210 | | int check_self(str* host, unsigned short port, unsigned short proto) |
211 | 0 | { |
212 | 0 | if (grep_sock_info(host, port, proto)) goto found; |
213 | | /* try to look into the aliases*/ |
214 | 0 | if (grep_aliases(host->s, host->len, port, proto)==0){ |
215 | 0 | LM_DBG("host != me\n"); |
216 | 0 | return 0; |
217 | 0 | } |
218 | 0 | found: |
219 | 0 | return 1; |
220 | 0 | } |
221 | | |
222 | | |
223 | | |
224 | | static inline int set_sl_branch(struct sip_msg* msg) |
225 | 0 | { |
226 | 0 | struct hdr_field *h_via; |
227 | 0 | struct via_body *b_via; |
228 | 0 | str *branch; |
229 | 0 | int via_parsed; |
230 | 0 | char b_md5[MD5_LEN]; |
231 | |
|
232 | 0 | via_parsed = 0; |
233 | 0 | branch = 0; |
234 | | |
235 | | /* first VIA header must be parsed */ |
236 | 0 | for( h_via=msg->h_via1 ; h_via ; h_via=h_via->sibling ) { |
237 | |
|
238 | 0 | b_via = (struct via_body*)h_via->parsed; |
239 | 0 | for( ; b_via ; b_via=b_via->next ) { |
240 | | /* check if there is any valid branch param */ |
241 | 0 | if (b_via->branch==0 || b_via->branch->value.s==0 |
242 | 0 | || b_via->branch->value.len==0 ) |
243 | 0 | continue; |
244 | 0 | branch = &b_via->branch->value; |
245 | | /* check if the branch param has the magic cookie */ |
246 | 0 | if (branch->len <= (int)MCOOKIE_LEN |
247 | 0 | || memcmp( branch->s, MCOOKIE, MCOOKIE_LEN)!=0 ) |
248 | 0 | continue; |
249 | | /* found a statefull branch -> use it */ |
250 | 0 | goto found; |
251 | 0 | } |
252 | | |
253 | 0 | if (!via_parsed) { |
254 | 0 | if ( parse_headers(msg,HDR_EOH_F,0)<0 ) { |
255 | 0 | LM_ERR("failed to parse all hdrs\n"); |
256 | 0 | return -1; |
257 | 0 | } |
258 | 0 | via_parsed = 1; |
259 | 0 | } |
260 | 0 | } |
261 | | |
262 | | /* no statefull branch :(.. -> use the branch from the last via */ |
263 | 0 | found: |
264 | 0 | if (branch==NULL) { |
265 | | /* no branch found :(.. -> try to use the From TAG param as |
266 | | * a value to seed the MD5 - the From TAG is per call, so it gives |
267 | | * a bit of uniqueness; if this is empty, as a last resort, use the |
268 | | * FROM URI (it cannot mis) */ |
269 | 0 | if ( parse_from_header(msg)!=0 ) |
270 | 0 | { |
271 | 0 | LM_ERR("failed to extract FROM header\n"); |
272 | 0 | return -1; |
273 | 0 | } |
274 | 0 | if ( get_from(msg)->tag_value.len ) |
275 | 0 | branch = &get_from(msg)->tag_value; |
276 | 0 | else |
277 | 0 | branch = &get_from(msg)->uri; |
278 | 0 | } |
279 | | |
280 | | /* make an MD5 over the found branch, to ensure a controlable |
281 | | * length of the resulting branch */ |
282 | 0 | MD5StringArray ( b_md5, branch, 1 ); |
283 | | /* and make a hash over transaction-related values */ |
284 | 0 | if ( parse_headers(msg, HDR_CALLID_F|HDR_CSEQ_F,0)==-1 || |
285 | 0 | msg->callid==NULL || msg->cseq==NULL ) |
286 | 0 | { |
287 | 0 | LM_ERR("failed to extract CALLID or CSEQ hdr from SIP msg\n"); |
288 | 0 | return -1; |
289 | 0 | } |
290 | | /* build the new branch */ |
291 | 0 | if (branch_builder( |
292 | 0 | core_hash( &msg->callid->body, &get_cseq(msg)->number, 1<<16 ), |
293 | 0 | 0 /*labled - not used here */, |
294 | 0 | b_md5, |
295 | 0 | 0 /*branch - not used here */, |
296 | 0 | msg->add_to_branch_s, &msg->add_to_branch_len )==0 ) |
297 | 0 | { |
298 | 0 | LM_ERR("branch_builder failed to construct the branch\n"); |
299 | 0 | return -1; |
300 | 0 | } |
301 | | |
302 | 0 | return 0; |
303 | 0 | } |
304 | | |
305 | | |
306 | | |
307 | | int forward_request( struct sip_msg* msg, struct proxy_l * p) |
308 | 0 | { |
309 | 0 | union sockaddr_union to; |
310 | 0 | str buf; |
311 | 0 | const struct socket_info* send_sock; |
312 | 0 | const struct socket_info* last_sock; |
313 | |
|
314 | 0 | buf.s=NULL; |
315 | | |
316 | | /* calculate branch for outbound request - if the branch buffer is already |
317 | | * set (maybe by an upper level as TM), used it; otherwise computes |
318 | | * the branch for stateless fwd. . According to the latest discussions |
319 | | * on the topic, you should reuse the latest statefull branch |
320 | | * --bogdan */ |
321 | 0 | if ( msg->add_to_branch_len==0 ) { |
322 | 0 | if (set_sl_branch(msg)!=0) { |
323 | 0 | LM_ERR("unable to compute and add stateless VIA branch\n"); |
324 | 0 | goto error; |
325 | 0 | } |
326 | 0 | } |
327 | | |
328 | 0 | msg_callback_process(msg, REQ_PRE_FORWARD, (void *)p); |
329 | |
|
330 | 0 | hostent2su( &to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT); |
331 | 0 | last_sock = 0; |
332 | |
|
333 | 0 | if (getb0flags(msg) & tcp_no_new_conn_bflag) |
334 | 0 | tcp_no_new_conn = 1; |
335 | |
|
336 | 0 | do { |
337 | 0 | send_sock=get_send_socket( msg, &to, p->proto); |
338 | 0 | if (send_sock==0){ |
339 | 0 | LM_ERR("cannot forward to af %d, proto %d no corresponding" |
340 | 0 | "listening socket\n", to.s.sa_family, p->proto); |
341 | 0 | ser_error=E_NO_SOCKET; |
342 | 0 | continue; |
343 | 0 | } |
344 | | |
345 | 0 | if ( last_sock!=send_sock ) { |
346 | |
|
347 | 0 | if (buf.s) |
348 | 0 | pkg_free(buf.s); |
349 | |
|
350 | 0 | buf.s = build_req_buf_from_sip_req( msg, (unsigned int*)&buf.len, |
351 | 0 | send_sock, p->proto, NULL, 0 /*flags*/); |
352 | 0 | if (!buf.s){ |
353 | 0 | LM_ERR("building req buf failed\n"); |
354 | 0 | tcp_no_new_conn = 0; |
355 | 0 | goto error; |
356 | 0 | } |
357 | | |
358 | 0 | last_sock = send_sock; |
359 | 0 | } |
360 | | |
361 | 0 | if (check_blacklists( p->proto, &to, buf.s, buf.len)) { |
362 | 0 | LM_DBG("blocked by blacklists\n"); |
363 | 0 | ser_error=E_IP_BLOCKED; |
364 | 0 | continue; |
365 | 0 | } |
366 | | |
367 | | /* send it! */ |
368 | 0 | LM_DBG("sending:\n%.*s.\n", buf.len, buf.s); |
369 | 0 | LM_DBG("orig. len=%d, new_len=%d, proto=%d\n", |
370 | 0 | msg->len, buf.len, p->proto ); |
371 | |
|
372 | 0 | if (msg_send(send_sock, p->proto, &to, 0, buf.s, buf.len, msg)<0){ |
373 | 0 | ser_error=E_SEND; |
374 | 0 | continue; |
375 | 0 | } |
376 | | |
377 | 0 | slcb_run_req_out( msg, &buf, &to, send_sock, p->proto); |
378 | |
|
379 | 0 | ser_error = 0; |
380 | 0 | break; |
381 | |
|
382 | 0 | }while( get_next_su( p, &to, (ser_error==E_IP_BLOCKED)?0:1)==0 ); |
383 | | |
384 | 0 | tcp_no_new_conn = 0; |
385 | |
|
386 | 0 | if (ser_error) { |
387 | 0 | update_stat( drp_reqs, 1); |
388 | 0 | goto error; |
389 | 0 | } |
390 | | |
391 | | /* sent requests stats */ |
392 | 0 | update_stat( fwd_reqs, 1); |
393 | |
|
394 | 0 | pkg_free(buf.s); |
395 | | /* received_buf & line_buf will be freed in receive_msg by free_lump_list*/ |
396 | 0 | return 0; |
397 | | |
398 | 0 | error: |
399 | 0 | if (buf.s) pkg_free(buf.s); |
400 | 0 | return -1; |
401 | 0 | } |
402 | | |
403 | | |
404 | | |
405 | | int update_sock_struct_from_via( union sockaddr_union* to, |
406 | | struct sip_msg* msg, |
407 | | struct via_body* via ) |
408 | 0 | { |
409 | 0 | struct hostent* he; |
410 | 0 | str* name; |
411 | 0 | int err; |
412 | 0 | unsigned short port; |
413 | |
|
414 | 0 | port=0; |
415 | 0 | if(via==msg->via1){ |
416 | | /* _local_ reply, we ignore any rport or received value |
417 | | * (but we will send back to the original port if rport is |
418 | | * present) */ |
419 | 0 | if ((msg->msg_flags&FL_FORCE_RPORT)||(via->rport)) |
420 | 0 | port=msg->rcv.src_port; |
421 | 0 | else port=via->port; |
422 | 0 | if(via->maddr) |
423 | 0 | name= &(via->maddr->value); |
424 | 0 | else |
425 | 0 | name=&(via->host); /* received=ip in 1st via is ignored (it's |
426 | | not added by us so it's bad) */ |
427 | 0 | }else{ |
428 | | /* "normal" reply, we use rport's & received value if present */ |
429 | 0 | if (via->rport && via->rport->value.s){ |
430 | 0 | LM_DBG("using 'rport'\n"); |
431 | 0 | port=str2s(via->rport->value.s, via->rport->value.len, &err); |
432 | 0 | if (err){ |
433 | 0 | LM_NOTICE("bad rport value(%.*s)\n", |
434 | 0 | via->rport->value.len,via->rport->value.s); |
435 | 0 | port=0; |
436 | 0 | } |
437 | 0 | } |
438 | |
|
439 | 0 | if (via->maddr){ |
440 | 0 | name= &(via->maddr->value); |
441 | 0 | if (port==0) port=via->port?via->port:SIP_PORT; |
442 | 0 | } else if (via->received){ |
443 | 0 | LM_DBG("using 'received'\n"); |
444 | 0 | name=&(via->received->value); |
445 | | /* making sure that we won't do SRV lookup on "received" */ |
446 | 0 | if (port==0) port=via->port?via->port:SIP_PORT; |
447 | 0 | }else{ |
448 | 0 | LM_DBG("using via host\n"); |
449 | 0 | name=&(via->host); |
450 | 0 | if (port==0) port=via->port; |
451 | 0 | } |
452 | 0 | } |
453 | 0 | LM_DBG("trying SRV lookup\n"); |
454 | 0 | he=sip_resolvehost(name, &port, &via->proto, 0, 0); |
455 | |
|
456 | 0 | if (he==0){ |
457 | 0 | LM_NOTICE("resolve_host(%.*s) failure\n", name->len, name->s); |
458 | 0 | return -1; |
459 | 0 | } |
460 | | |
461 | 0 | hostent2su( to, he, 0, port); |
462 | 0 | return 1; |
463 | 0 | } |
464 | | |
465 | | |
466 | | |
467 | | /*! \brief removes first via & sends msg to the second */ |
468 | | int forward_reply(struct sip_msg* msg) |
469 | 0 | { |
470 | 0 | char* new_buf; |
471 | 0 | union sockaddr_union* to; |
472 | 0 | unsigned int new_len; |
473 | 0 | struct sr_module *mod; |
474 | 0 | int proto; |
475 | 0 | unsigned int id; /* used only by tcp*/ |
476 | 0 | const struct socket_info *send_sock; |
477 | 0 | char* s; |
478 | 0 | int len; |
479 | |
|
480 | 0 | to=0; |
481 | 0 | id=0; |
482 | 0 | new_buf=0; |
483 | | /*check if first via host = us */ |
484 | 0 | if (check_via){ |
485 | 0 | if (check_self(&msg->via1->host, |
486 | 0 | msg->via1->port?msg->via1->port:SIP_PORT, |
487 | 0 | msg->via1->proto)!=1){ |
488 | 0 | LM_ERR("host in first via!=me : %.*s:%d\n", |
489 | 0 | msg->via1->host.len, msg->via1->host.s, msg->via1->port); |
490 | | /* send error msg back? */ |
491 | 0 | goto error; |
492 | 0 | } |
493 | 0 | } |
494 | | /* quick hack, slower for multiple modules*/ |
495 | 0 | for (mod=modules;mod;mod=mod->next){ |
496 | 0 | if ((mod->exports) && (mod->exports->response_f)){ |
497 | 0 | LM_DBG("found module %s, passing reply to it\n", |
498 | 0 | mod->exports->name); |
499 | 0 | if (mod->exports->response_f(msg)==0) goto skip; |
500 | 0 | } |
501 | 0 | } |
502 | | |
503 | | /* if stateless fwd was disabled, we cannot have stateless replies here*/ |
504 | 0 | if (sl_fwd_disabled) |
505 | 0 | goto skip; |
506 | | |
507 | | /* we have to forward the reply stateless, so we need second via -bogdan*/ |
508 | 0 | if (parse_headers( msg, HDR_VIA2_F, 0 )==-1 |
509 | 0 | || (msg->via2==0) || (msg->via2->error!=PARSE_OK)) |
510 | 0 | { |
511 | | /* no second via => error */ |
512 | 0 | LM_ERR("no 2nd via found in [%.*s] [%.*s] reply from [%s] for callid [%.*s]\n", |
513 | 0 | msg->first_line.u.reply.status.len, msg->first_line.u.reply.status.s, |
514 | 0 | msg->cseq->body.len, msg->cseq->body.s, |
515 | 0 | ip_addr2a(&msg->rcv.src_ip), |
516 | 0 | msg->callid->body.len, msg->callid->body.s); |
517 | 0 | goto error; |
518 | 0 | } |
519 | | |
520 | 0 | to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union)); |
521 | 0 | if (to==0){ |
522 | 0 | LM_ERR("out of pkg memory\n"); |
523 | 0 | goto error; |
524 | 0 | } |
525 | | |
526 | 0 | proto=msg->via2->proto; |
527 | 0 | if (update_sock_struct_from_via( to, msg, msg->via2 )==-1) goto error; |
528 | | |
529 | 0 | if (is_tcp_based_proto(proto)){ |
530 | | /* find id in i param if it exists */ |
531 | 0 | if (msg->via1->i&&msg->via1->i->value.s){ |
532 | 0 | s=msg->via1->i->value.s; |
533 | 0 | len=msg->via1->i->value.len; |
534 | 0 | if (reverse_hex2int(s, len, &id)<0) |
535 | 0 | id = 0; |
536 | 0 | } |
537 | 0 | } |
538 | |
|
539 | 0 | send_sock = get_send_socket(msg, to, proto); |
540 | |
|
541 | 0 | new_buf = build_res_buf_from_sip_res( msg, &new_len, send_sock,0); |
542 | 0 | if (!new_buf){ |
543 | 0 | LM_ERR("failed to build rpl from req failed\n"); |
544 | 0 | goto error; |
545 | 0 | } |
546 | | |
547 | 0 | if (msg->flags & tcp_no_new_conn_rplflag) |
548 | 0 | tcp_no_new_conn = 1; |
549 | |
|
550 | 0 | if (msg_send(send_sock, proto, to, id, new_buf, new_len, msg)<0) { |
551 | 0 | tcp_no_new_conn = 0; |
552 | 0 | update_stat( drp_rpls, 1); |
553 | 0 | goto error0; |
554 | 0 | } |
555 | 0 | tcp_no_new_conn = 0; |
556 | |
|
557 | 0 | update_stat( fwd_rpls, 1); |
558 | | /* |
559 | | * If no port is specified in the second via, then this |
560 | | * message output a wrong port number - zero. Despite that |
561 | | * the correct port is choosen in update_sock_struct_from_via, |
562 | | * as its visible with su_getport(to); . |
563 | | */ |
564 | 0 | LM_DBG("reply forwarded to %.*s:%d\n", msg->via2->host.len, |
565 | 0 | msg->via2->host.s, (unsigned short) msg->via2->port); |
566 | |
|
567 | 0 | pkg_free(new_buf); |
568 | 0 | pkg_free(to); |
569 | 0 | skip: |
570 | 0 | return 0; |
571 | 0 | error: |
572 | 0 | update_stat( err_rpls, 1); |
573 | 0 | error0: |
574 | 0 | if (new_buf) pkg_free(new_buf); |
575 | 0 | if (to) pkg_free(to); |
576 | 0 | return -1; |
577 | 0 | } |