that is "temporary" DOWN (dial up internet access) if outbounf IF is down, send back a response to inbound UAs "408 Request Timeout". - always log to syslog, also when running in foreground - changed some WARNINGS into DEBUG statements - re-arranged some code - rtpproxy: prepared for proper thread termination on exit - introduced short term caching for get_ip_by_ifname - fixed in check for socket() return status
715 lines
21 KiB
C
715 lines
21 KiB
C
/*
|
|
Copyright (C) 2002 Thomas Ries <tries@gmx.net>
|
|
|
|
This file is part of Siproxd.
|
|
|
|
Siproxd is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Siproxd is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Siproxd; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
#ifdef HAVE_OSIP2
|
|
#include <osip2/smsg.h>
|
|
#include <osip2/sdp.h>
|
|
#else
|
|
#include <osip/smsg.h>
|
|
#include <osip/sdp.h>
|
|
#endif
|
|
|
|
#include "siproxd.h"
|
|
#include "log.h"
|
|
|
|
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
|
BUILDSTR " $";
|
|
|
|
|
|
/* configuration storage */
|
|
extern struct siproxd_config configuration;
|
|
|
|
extern int errno;
|
|
extern struct urlmap_s urlmap[]; /* URL mapping table */
|
|
extern struct lcl_if_s local_addresses;
|
|
extern int sip_socket; /* sending SIP datagrams */
|
|
|
|
|
|
/*
|
|
* PROXY_REQUEST
|
|
*
|
|
* RETURNS
|
|
* STS_SUCCESS on success
|
|
* STS_FAILURE on error
|
|
*/
|
|
int proxy_request (sip_t *request) {
|
|
int i;
|
|
int sts;
|
|
int type;
|
|
struct in_addr sendto_addr;
|
|
contact_t *contact;
|
|
url_t *url;
|
|
int port;
|
|
char *buffer;
|
|
|
|
#define REQTYP_INCOMING 1
|
|
#define REQTYP_OUTGOING 2
|
|
|
|
DEBUGC(DBCLASS_PROXY,"proxy_request");
|
|
|
|
/* check for VIA loop, if yes, discard the request */
|
|
sts=check_vialoop(request);
|
|
if (sts == STS_TRUE) {
|
|
DEBUGC(DBCLASS_PROXY,"via loop detected, ignoring request");
|
|
/* according to the SIP RFC we are supposed to return an 482 error */
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
type = 0;
|
|
for (i=0; i<URLMAP_SIZE; i++) {
|
|
if (urlmap[i].active == 0) continue;
|
|
|
|
/* incoming request ('to' == 'masq') */
|
|
if (compare_url(request->to->url, urlmap[i].masq_url)==STS_SUCCESS) {
|
|
type=REQTYP_INCOMING;
|
|
DEBUGC(DBCLASS_PROXY,"incoming request from %s@%s from outbound",
|
|
request->from->url->username? request->from->url->username:"*NULL*",
|
|
request->from->url->host? request->from->url->host: "*NULL*");
|
|
break;
|
|
}
|
|
|
|
/* outgoing request ('from' == 'reg') */
|
|
if (compare_url(request->from->url, urlmap[i].reg_url)==STS_SUCCESS) {
|
|
type=REQTYP_OUTGOING;
|
|
DEBUGC(DBCLASS_PROXY,"outgoing request from %s@%s from inbound",
|
|
request->from->url->username? request->from->url->username:"*NULL*",
|
|
request->from->url->host? request->from->url->host: "*NULL*");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* ok, we got a request that we are allowed to process.
|
|
*/
|
|
#ifdef HACK1
|
|
/* linphone-0.9.0pre4
|
|
take To address and place it into URI (at least the host part)
|
|
Linphone-0.9.0pre4 puts the proxy host in the request URI
|
|
if OUTBOUND proxy is activated!
|
|
This is only a hack to recreate the proper final request URI.
|
|
This issue has been fixed in 0.9.1pre1
|
|
*/
|
|
{
|
|
header_t *header_ua;
|
|
|
|
url=msg_geturi(request);
|
|
msg_getuser_agent(request,0,&header_ua);
|
|
|
|
if ( header_ua && header_ua->hvalue &&
|
|
(strcmp(header_ua->hvalue,"oSIP/Linphone-0.8.0")==0) ) {
|
|
/* if an outgoing request, try to fix the SIP URI */
|
|
if (type == REQTYP_OUTGOING) {
|
|
WARN("broken linphone-0.8.0: restoring SIP URI");
|
|
free (url->host);
|
|
url->host=malloc(strlen(request->to->url->host));
|
|
strcpy(url->host,request->to->url->host);
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
switch (type) {
|
|
/*
|
|
* from an external host to the internal masqueraded host
|
|
*/
|
|
case REQTYP_INCOMING:
|
|
sts = get_ip_by_host(urlmap[i].true_url->host, &sendto_addr);
|
|
if (sts == STS_FAILURE) {
|
|
DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]",
|
|
url->host);
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* rewrite request URI to point to the real host */
|
|
/* i still holds the valid index into the URLMAP table */
|
|
if (check_rewrite_rq_uri(request)==STS_TRUE) {
|
|
proxy_rewrite_request_uri(request, i);
|
|
}
|
|
|
|
/* add my Via header line (inbound interface)*/
|
|
sts = sip_add_myvia(request, IF_INBOUND);
|
|
if (sts == STS_FAILURE) {
|
|
ERROR("adding my inbound via failed!");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* if this is CANCEL/BYE request, stop RTP proxying */
|
|
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
|
|
/* stop the RTP proxying stream */
|
|
rtp_stop_fwd(msg_getcall_id(request), 0);
|
|
}
|
|
|
|
break;
|
|
|
|
/*
|
|
* from the internal masqueraded host to an external host
|
|
*/
|
|
case REQTYP_OUTGOING:
|
|
/* get destination address */
|
|
url=msg_geturi(request);
|
|
|
|
sts = get_ip_by_host(url->host, &sendto_addr);
|
|
if (sts == STS_FAILURE) {
|
|
DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]",
|
|
url->host);
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* if it is addressed to myself, then it must be some request
|
|
* method that I as a proxy do not support. Reject */
|
|
if (is_sipuri_local(request) == STS_TRUE) {
|
|
WARN("unsupported request [%s] directed to proxy from %s@%s -> %s@%s",
|
|
request->strtline->sipmethod? request->strtline->sipmethod:"*NULL*",
|
|
request->from->url->username? request->from->url->username:"*NULL*",
|
|
request->from->url->host? request->from->url->host : "*NULL*",
|
|
url->username? url->username : "*NULL*",
|
|
url->host? url->host : "*NULL*");
|
|
|
|
sip_gen_response(request, 403 /*forbidden*/);
|
|
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* if an INVITE, rewrite body */
|
|
if (MSG_IS_INVITE(request)) {
|
|
sts = proxy_rewrite_invitation_body(request);
|
|
}
|
|
|
|
/* rewrite Contact header to represent the masqued address */
|
|
msg_getcontact(request,0,&contact);
|
|
if (contact != NULL) {
|
|
for (i=0;i<URLMAP_SIZE;i++){
|
|
if (urlmap[i].active == 0) continue;
|
|
if (compare_url(contact->url, urlmap[i].true_url)==STS_SUCCESS)
|
|
break;
|
|
}
|
|
/* found a mapping entry */
|
|
if (i<URLMAP_SIZE) {
|
|
DEBUGC(DBCLASS_PROXY, "rewrote Contact header %s@%s -> %s@%s",
|
|
(contact->url->username)? contact->url->username : "*NULL*",
|
|
(contact->url->host)? contact->url->host : "*NULL*",
|
|
urlmap[i].masq_url->username, urlmap[i].masq_url->host);
|
|
/* remove old entry */
|
|
list_remove(request->contacts,0);
|
|
contact_free(contact);
|
|
free(contact);
|
|
/* clone the masquerading url */
|
|
contact_init(&contact);
|
|
url_clone(urlmap[i].masq_url, &contact->url);
|
|
list_add(request->contacts,contact,-1);
|
|
}
|
|
}
|
|
|
|
/* add my Via header line (outbound interface)*/
|
|
sts = sip_add_myvia(request, IF_OUTBOUND);
|
|
if (sts == STS_FAILURE) {
|
|
ERROR("adding my outbound via failed!");
|
|
}
|
|
|
|
/* if this is CANCEL/BYE request, stop RTP proxying */
|
|
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
|
|
rtp_stop_fwd(msg_getcall_id(request), 0);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
url=msg_geturi(request);
|
|
DEBUGC(DBCLASS_PROXY, "request [%s] from/to unregistered UA "
|
|
"(RQ: %s@%s -> %s@%s)",
|
|
request->strtline->sipmethod? request->strtline->sipmethod:"*NULL*",
|
|
request->from->url->username? request->from->url->username:"*NULL*",
|
|
request->from->url->host? request->from->url->host : "*NULL*",
|
|
url->username? url->username : "*NULL*",
|
|
url->host? url->host : "*NULL*");
|
|
|
|
/*
|
|
* we may end up here for two reasons:
|
|
* 1) An incomming request (from outbound) that is directed to
|
|
* an unknown (not registered) local UA
|
|
* 2) an outgoing request from a local UA that is not registered.
|
|
*
|
|
* Case 1) we should probably answer with "404 Not Found",
|
|
* case 2) more likely a "403 Forbidden"
|
|
*
|
|
* How about "408 Request Timeout" ?
|
|
*
|
|
*/
|
|
sip_gen_response(request, 408 /* Request Timeout */);
|
|
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
|
|
sts = msg_2char(request, &buffer);
|
|
if (sts != 0) {
|
|
ERROR("proxy_request: msg_2char failed");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* send to destination */
|
|
if (url->port) {
|
|
port=atoi(url->port);
|
|
} else {
|
|
port=SIP_PORT;
|
|
}
|
|
|
|
sipsock_send_udp(&sip_socket, sendto_addr, port, buffer, strlen(buffer), 1);
|
|
free (buffer);
|
|
return STS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* PROXY_RESPONSE
|
|
*
|
|
* RETURNS
|
|
* STS_SUCCESS on success
|
|
* STS_FAILURE on error
|
|
*/
|
|
int proxy_response (sip_t *response) {
|
|
int i;
|
|
int sts;
|
|
int type;
|
|
struct in_addr addr;
|
|
via_t *via;
|
|
contact_t *contact;
|
|
int port;
|
|
char *buffer;
|
|
|
|
#define RESTYP_INCOMING 1
|
|
#define RESTYP_OUTGOING 2
|
|
|
|
DEBUGC(DBCLASS_PROXY,"proxy_response");
|
|
|
|
|
|
/* check for VIA loop, if yes, discard the request */
|
|
sts=check_vialoop(response);
|
|
if (sts == STS_TRUE) {
|
|
DEBUGC(DBCLASS_PROXY,"via loop detected, ignoring response");
|
|
/* according to the SIP RFC we are supposed to return an 482 error */
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* ALWAYS: remove my Via header line */
|
|
sts = sip_del_myvia(response);
|
|
if (sts == STS_FAILURE) {
|
|
DEBUGC(DBCLASS_PROXY,"not addressed to my VIA, ignoring response");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* figure out if this is an request coming from the outside
|
|
* world to one of our registered clients
|
|
*/
|
|
|
|
|
|
/* Ahhrghh...... an response seems to have NO contact information...
|
|
* so let's take FROM instead...
|
|
* the TO and FROM headers are EQUAL to the request - that means
|
|
* they are swapped in their meaning for a response...
|
|
*/
|
|
|
|
type = 0;
|
|
for (i=0; i<URLMAP_SIZE; i++) {
|
|
if (urlmap[i].active == 0) continue;
|
|
|
|
|
|
/* incoming response ('from' == 'masq') */
|
|
if (compare_url(response->from->url, urlmap[i].masq_url)==STS_SUCCESS) {
|
|
type=RESTYP_INCOMING;
|
|
DEBUGC(DBCLASS_PROXY,"incoming response for %s@%s from outbound",
|
|
response->from->url->username? response->from->url->username:"*NULL*",
|
|
response->from->url->host? response->from->url->host : "*NULL*");
|
|
break;
|
|
}
|
|
|
|
/* outgoing response ('to' == 'reg') */
|
|
if (compare_url(response->to->url, urlmap[i].masq_url)==STS_SUCCESS) {
|
|
type=RESTYP_OUTGOING;
|
|
DEBUGC(DBCLASS_PROXY,"outgoing response for %s@%s from inbound",
|
|
response->from->url->username? response->from->url->username:"*NULL*",
|
|
response->from->url->host? response->from->url->host : "*NULL*");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ok, we got a response that we are allowed to process.
|
|
*/
|
|
switch (type) {
|
|
/*
|
|
* from an external host to the internal masqueraded host
|
|
*/
|
|
case RESTYP_INCOMING:
|
|
break;
|
|
|
|
/*
|
|
* from the internal masqueraded host to an external host
|
|
*/
|
|
case RESTYP_OUTGOING:
|
|
#define satoi atoi /* used in MSG_TEST_CODE macro ... */
|
|
/* If an 200 answer to an INVITE request, rewrite body */
|
|
if ((MSG_IS_RESPONSEFOR(response,"INVITE")) &&
|
|
(MSG_TEST_CODE(response, 200))) {
|
|
sts = proxy_rewrite_invitation_body(response);
|
|
}
|
|
|
|
/* rewrite Contact header to represent the masqued address */
|
|
msg_getcontact(response,0,&contact);
|
|
if (contact != NULL) {
|
|
for (i=0;i<URLMAP_SIZE;i++){
|
|
if (urlmap[i].active == 0) continue;
|
|
if (compare_url(contact->url, urlmap[i].true_url)==STS_SUCCESS)
|
|
break;
|
|
}
|
|
/* found a mapping entry */
|
|
if (i<URLMAP_SIZE) {
|
|
DEBUGC(DBCLASS_PROXY, "rewrote Contact header %s@%s -> %s@%s",
|
|
(contact->url->username) ? contact->url->username:"*NULL*",
|
|
(contact->url->host) ? contact->url->host : "*NULL*",
|
|
urlmap[i].masq_url->username, urlmap[i].masq_url->host);
|
|
/* remove old entry */
|
|
list_remove(response->contacts,0);
|
|
contact_free(contact);
|
|
free(contact);
|
|
/* clone the masquerading url */
|
|
contact_init(&contact);
|
|
url_clone(urlmap[i].masq_url, &contact->url);
|
|
list_add(response->contacts,contact,-1);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
DEBUGC(DBCLASS_PROXY, "response from/to unregistered UA (%s@%s)",
|
|
response->from->url->username? response->from->url->username:"*NULL*",
|
|
response->from->url->host? response->from->url->host : "*NULL*");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* get target address from VIA header */
|
|
via = (via_t *) list_get (response->vias, 0);
|
|
if (via == NULL) {
|
|
ERROR("proxy_response: list_get via failed");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
sts = get_ip_by_host(via->host, &addr);
|
|
if (sts == STS_FAILURE) {
|
|
DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve via [%s]",
|
|
via->host);
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
sts = msg_2char(response, &buffer);
|
|
if (sts != 0) {
|
|
ERROR("proxy_response: msg_2char failed");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/* send to destination */
|
|
if (via->port) {
|
|
port=atoi(via->port);
|
|
} else {
|
|
port=SIP_PORT;
|
|
}
|
|
|
|
sipsock_send_udp(&sip_socket, addr, port, buffer, strlen(buffer), 1);
|
|
free (buffer);
|
|
return STS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* PROXY_REWRITE_INVITATION_BODY
|
|
*
|
|
* rewrites the outgoing INVITATION packet
|
|
*
|
|
* RETURNS
|
|
* STS_SUCCESS on success
|
|
* STS_FAILURE on error
|
|
*/
|
|
int proxy_rewrite_invitation_body(sip_t *mymsg){
|
|
body_t *body;
|
|
sdp_t *sdp;
|
|
struct in_addr outb_addr, lcl_clnt_addr;
|
|
int sts;
|
|
char *oldbody;
|
|
char newbody[BODY_MESSAGE_MAX_SIZE];
|
|
char clen[8]; /* content length: probably never more than 7 digits !*/
|
|
int outb_rtp_port, inb_clnt_port;
|
|
int media_stream_no;
|
|
|
|
sts = msg_getbody(mymsg, 0, &body);
|
|
if (sts != 0) {
|
|
ERROR("rewrite_invitation_body: no body found in message");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
sts = body_2char(body, &oldbody);
|
|
|
|
sts = sdp_init(&sdp);
|
|
sts = sdp_parse (sdp, oldbody);
|
|
if (sts != 0) {
|
|
ERROR("rewrite_invitation_body: unable to sdp_parse body");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
{ /* just dump the buffer */
|
|
char *tmp2;
|
|
content_length_2char(mymsg->contentlength, &tmp2);
|
|
DEBUG("Body before rewrite (clen=%s, strlen=%i):\n%s\n----",
|
|
tmp2, strlen(oldbody), oldbody);
|
|
free(tmp2);
|
|
}
|
|
|
|
|
|
/*
|
|
* RTP proxy: get ready and start forwarding
|
|
* start forwarding for each media stream ('m=' item in SIP message)
|
|
*/
|
|
sts = get_ip_by_host(sdp_c_addr_get(sdp,-1,0), &lcl_clnt_addr);
|
|
if (sts == STS_FAILURE) {
|
|
DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: cannot resolve "
|
|
"m= (media) host [%s]", sdp_c_addr_get(sdp,-1,0));
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
sts = get_ip_by_ifname(configuration.outbound_if, &outb_addr);
|
|
if (sts == STS_FAILURE) {
|
|
ERROR("can't find outbound interface %s - configuration error?",
|
|
configuration.inbound_if);
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
for (media_stream_no=0;;media_stream_no++) {
|
|
/* check if n'th media stream is present */
|
|
if (sdp_m_port_get(sdp, media_stream_no) == NULL) break;
|
|
|
|
/* start an RTP proxying stream */
|
|
if (sdp_m_port_get(sdp, media_stream_no)) {
|
|
inb_clnt_port=atoi(sdp_m_port_get(sdp, media_stream_no));
|
|
rtp_start_fwd(msg_getcall_id(mymsg), media_stream_no,
|
|
outb_addr, &outb_rtp_port,
|
|
lcl_clnt_addr, inb_clnt_port);
|
|
} else {
|
|
/* no port defined - skip entry */
|
|
continue;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* yup, I know - here are some HARDCODED strings that we
|
|
* search for in the connect information and media description
|
|
* in the SDP part of the INVITE packet
|
|
*
|
|
* TODO: redo the rewriting section below,
|
|
* using the nice sdp_ routines of libosip!
|
|
*
|
|
* Up to now, also only ONE incoming media port per session
|
|
* is supported! I guess, there may be more allowed.
|
|
*/
|
|
{
|
|
char *data_c=NULL; /* connection information 'c=' line*/
|
|
char *data_m=NULL; /* media description 'm=' line*/
|
|
char *data2_c=NULL; /* end of IP address on 'c=' line */
|
|
char *data2_m=NULL; /* end of port number on 'm=' line */
|
|
char *ptr=NULL;
|
|
|
|
memset(newbody, 0, sizeof(newbody));
|
|
|
|
/*
|
|
* find where to patch connection information (IP address)
|
|
*/
|
|
data_c = strstr (oldbody, "\nc=");
|
|
if (data_c == NULL) data_c = strstr (oldbody, "\rc=");
|
|
if (data_c == NULL) {
|
|
ERROR("did not find a c= line in the body");
|
|
return STS_FAILURE;
|
|
}
|
|
data_c += 3;
|
|
/* can only rewrite IPV4 addresses by now */
|
|
if (strncmp(data_c,"IN IP4 ",7)!=0) {
|
|
ERROR("c= does not contain an IN IP4 address");
|
|
return STS_FAILURE;
|
|
}
|
|
data_c += 7; /* PTR to start of IP address */
|
|
/* find the end of the IP address -> end of line */
|
|
data2_c = strstr (data_c, "\n");
|
|
if (data2_c == NULL) data2_c = strstr (oldbody, "\r");
|
|
if (data2_c == NULL) {
|
|
ERROR("did not find a CR/LF after c= line");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* find where to patch media description (port number)
|
|
*/
|
|
data_m = strstr (oldbody, "\nm=");
|
|
if (data_m == NULL) data_m = strstr (oldbody, "\rm=");
|
|
if (data_m == NULL) {
|
|
ERROR("did not find a m= line in the body");
|
|
return STS_FAILURE;
|
|
}
|
|
data_m += 3;
|
|
/* check for audio media */
|
|
if (strncmp(data_m,"audio ",6)!=0) {
|
|
ERROR("m= does not contain audio");
|
|
return STS_FAILURE;
|
|
}
|
|
data_m += 6; /* PTR to start of port number */
|
|
/* find the end of the IP address -> end of line */
|
|
data2_m = strstr (data_m, " RTP/");
|
|
if (data2_m == NULL) {
|
|
ERROR("did not find RTP/ on m= line");
|
|
return STS_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* what is first? c= or m= ?
|
|
* (Im sure this can be made nicer)
|
|
*/
|
|
if (data_c < data_m) {
|
|
DEBUGC(DBCLASS_PROXY,"c= before m=");
|
|
/*
|
|
* c= line first, replace IP address, then port
|
|
*/
|
|
/* copy up to the to-be-masqueraded address */
|
|
memcpy(newbody, oldbody, data_c-oldbody);
|
|
/* insert proxy outbound address */
|
|
ptr=newbody+(data_c-oldbody);
|
|
sprintf(ptr, "%s", inet_ntoa(outb_addr));
|
|
ptr += strlen(ptr);
|
|
/* copy up to the m= line */
|
|
memcpy (ptr, data2_c, data_m-data2_c);
|
|
ptr += strlen(ptr);
|
|
/* substitute port number */
|
|
sprintf(ptr, "%i", outb_rtp_port);
|
|
ptr += strlen(ptr);
|
|
/* copy the rest */
|
|
memcpy (ptr, data2_m, strlen(data2_m));
|
|
} else {
|
|
DEBUGC(DBCLASS_PROXY,"m= before c=");
|
|
/*
|
|
* m= line first, replace port, then IP address
|
|
*/
|
|
/* copy up to the to-be-masqueraded port */
|
|
memcpy(newbody, oldbody, data_m-oldbody);
|
|
ptr=newbody+(data_m-oldbody);
|
|
/* substitute port number */
|
|
sprintf(ptr, "%i", outb_rtp_port);
|
|
ptr += strlen(ptr);
|
|
/* copy up to the c= line */
|
|
memcpy (ptr, data2_m, data_c-data2_m);
|
|
ptr += strlen(ptr);
|
|
/* insert proxy outbound address */
|
|
sprintf(ptr, "%s", inet_ntoa(outb_addr));
|
|
ptr += strlen(ptr);
|
|
/* copy the rest */
|
|
memcpy (ptr, data2_c, strlen(data2_c));
|
|
}
|
|
|
|
}
|
|
|
|
/* remove old body */
|
|
sts = list_remove(mymsg->bodies, 0);
|
|
body_free(body);
|
|
free(body);
|
|
/* free sdp structure */
|
|
sdp_free(sdp);
|
|
free(sdp);
|
|
|
|
/* include new body */
|
|
msg_setbody(mymsg, newbody);
|
|
|
|
/* free content length resource and include new one*/
|
|
content_length_free(mymsg->contentlength);
|
|
free(mymsg->contentlength);
|
|
mymsg->contentlength=NULL;
|
|
sprintf(clen,"%i",strlen(newbody));
|
|
sts = msg_setcontent_length(mymsg, clen);
|
|
|
|
|
|
{ /* just dump the buffer */
|
|
char *tmp, *tmp2;
|
|
sts = msg_getbody(mymsg, 0, &body);
|
|
sts = body_2char(body, &tmp);
|
|
content_length_2char(mymsg->contentlength, &tmp2);
|
|
DEBUG("Body after rewrite (clen=%s, strlen=%i):\n%s\n----",
|
|
tmp2, strlen(tmp), tmp);
|
|
free(tmp);
|
|
free(tmp2);
|
|
}
|
|
free(oldbody);
|
|
return STS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* PROXY_REWRITE_INVITATION_BODY
|
|
*
|
|
* rewrites the outgoing INVITATION packet
|
|
*
|
|
* RETURNS
|
|
* STS_SUCCESS on success
|
|
*/
|
|
int proxy_rewrite_request_uri(sip_t *mymsg, int idx){
|
|
char *host;
|
|
char *port;
|
|
url_t *url;
|
|
|
|
DEBUGC(DBCLASS_PROXY,"rewriting incoming Request URI");
|
|
url=msg_geturi(mymsg);
|
|
free(url->host);url->host=NULL;
|
|
|
|
/* set the true host */
|
|
if(urlmap[idx].true_url->host) {
|
|
host = (char *)malloc(strlen(urlmap[idx].true_url->host)+1);
|
|
memcpy(host, urlmap[idx].true_url->host, strlen(urlmap[idx].true_url->host));
|
|
host[strlen(urlmap[idx].true_url->host)]='\0';
|
|
url_sethost(url, host);
|
|
}
|
|
|
|
/* set the true port */
|
|
if(urlmap[idx].true_url->port) {
|
|
port = (char *)malloc(strlen(urlmap[idx].true_url->port)+1);
|
|
memcpy(port, urlmap[idx].true_url->port, strlen(urlmap[idx].true_url->port));
|
|
port[strlen(urlmap[idx].true_url->port)]='\0';
|
|
url_setport(url, port);
|
|
}
|
|
return STS_SUCCESS;
|
|
}
|