Release 0.1.2
includes experimantal RTP data stream proxy
This commit is contained in:
@@ -1,9 +1,17 @@
|
||||
0.1.2
|
||||
=====
|
||||
- 7-Sep-2002: Releases version 0.1.2
|
||||
Experimental RTP proxying feature (using pthreads)
|
||||
- 26-Aug-2002: Optimized DNS caching
|
||||
|
||||
0.1.1
|
||||
=====
|
||||
- 25-Aug-2002: Released version 0.1.1
|
||||
can daemonize (detach and run in background)
|
||||
do some DNS caching
|
||||
- 24-Aug-2002: Imlemented support for a config file,
|
||||
obsoletes siproxd_conf.h
|
||||
|
||||
0.1.0
|
||||
=====
|
||||
- 19-Aug-2002: Released version 0.1.0
|
||||
- 19-Aug-2002: Released version 0.1.0
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
|
||||
|
||||
Be warned, this (and all the other) documentantation is far from
|
||||
complete. This is just a *very* preliminary pre-alpha release. Don't
|
||||
expect anything!
|
||||
complete. This is still considered an alpha release.
|
||||
|
||||
|
||||
Overview:
|
||||
@@ -26,7 +25,7 @@ Requirements:
|
||||
- libosip-0.8.8 (http://www.fsf.org/software/osip/)
|
||||
|
||||
Up to now, this packages only has been tested under an i386 Redhat Linux 6.0.
|
||||
However, it should build and run under newer versions.
|
||||
However, it should build and run under newer versions (feedback is welcome).
|
||||
|
||||
|
||||
|
||||
@@ -49,25 +48,41 @@ How to get started:
|
||||
here and use a dynamic DNS service like dyndns.org)
|
||||
|
||||
|
||||
|
||||
What siproxd does:
|
||||
=================
|
||||
Siproxd's main purpose (up to now) is to rewrite SIP messages.
|
||||
Siproxd's main purpose (up to now) is to rewrite SIP messages
|
||||
to be able to operate via an masquerading firewall.
|
||||
Since release 0.1.2 siproxd can proxy incomming RTP streams.
|
||||
|
||||
|
||||
|
||||
What siproxd does NOT do:
|
||||
=========================
|
||||
Siproxd does *not* (yet) create masquerading tunnels or port-forwarding
|
||||
for the data stream through the firewall.
|
||||
|
||||
These forwarding rules have to be set-up manually.
|
||||
SINCE RELEASE 0.1.2:
|
||||
Siproxd should be able to proxy incomming RTP data streams (UDP only).
|
||||
This is still very experimental code ;-)
|
||||
The config parameters 'rtp_port_low' and rtp_port_high' define
|
||||
the port range that siproxd will use for incomming RTP data streams.
|
||||
'rtp_timeout' defines after what time an unused (no data received)
|
||||
rtp stream is considered dead and removed.
|
||||
|
||||
** As I had not yet the possibility to test this feature,
|
||||
** I'd be glad about feedback.
|
||||
|
||||
Example, using ipchains (mfw):
|
||||
# ipchains -A input --proto udp --dport 7078 -m 100 -j ACCEPT
|
||||
# ipmasqadm mfw -A -m 100 -r <remoteaddress> 7078
|
||||
PRIOR TO RELEASE 0.1.2:
|
||||
Siproxd does *not* (yet) create masquerading tunnels or port-forwarding
|
||||
for the data stream through the firewall.
|
||||
|
||||
Example, using ipchains (portfw):
|
||||
# portfw -a -P udp -L <localaddress> 7078 -R <remoteaddress> 7078
|
||||
These forwarding rules have to be set-up manually (currently)
|
||||
|
||||
Example, using ipchains (mfw):
|
||||
# ipchains -A input --proto udp --dport 7078 -m 100 -j ACCEPT
|
||||
# ipmasqadm mfw -A -m 100 -r <remoteaddress> 7078
|
||||
|
||||
Example, using ipchains (portfw):
|
||||
# portfw -a -P udp -L <localaddress> 7078 -R <remoteaddress> 7078
|
||||
|
||||
|
||||
|
||||
@@ -80,17 +95,23 @@ Limitations:
|
||||
|
||||
Important Notice:
|
||||
=================
|
||||
gethostbyname() leaks memory in RedHat 6.0 with glibc 2.1.1.
|
||||
|
||||
The gethostbyname() function leaks memory in RedHat 6.0 with glibc 2.1.1.
|
||||
The quick fix is to delete nisplus service from hosts entry in
|
||||
/etc/nsswitch.conf. In my tests, memory use remained stable
|
||||
after I made the above change.
|
||||
(->http://www.squid-cache.org/Doc/FAQ/FAQ-14.html)
|
||||
/etc/nsswitch.conf. In my tests, memory use remained stable after I
|
||||
made the mentioned change.
|
||||
(source: http://www.squid-cache.org/Doc/FAQ/FAQ-14.html)
|
||||
|
||||
|
||||
Contacts:
|
||||
=========
|
||||
Please feel free to contact the author to:
|
||||
- provide feedback
|
||||
- report bugs,
|
||||
- request for additional features
|
||||
- report interoperability with softphones
|
||||
- ...
|
||||
|
||||
and visit the website at http://siproxd.sourceforge.net/
|
||||
|
||||
Thomas Ries (tries@gmx.net)
|
||||
GnuPG Public Key:
|
||||
|
||||
@@ -13,3 +13,6 @@ TODOs, in anarchistic order:
|
||||
- logging via syslog if running in daemon mode
|
||||
|
||||
- get_ip_by_host: reduce DNS timeouts
|
||||
|
||||
- forwarding(proxying) of incomming RTP media streams
|
||||
? own thread/process (is pending)
|
||||
|
||||
@@ -48,6 +48,9 @@
|
||||
/* Define if you have the osip library (-losip). */
|
||||
#undef HAVE_LIBOSIP
|
||||
|
||||
/* Define if you have the pthread library (-lpthread). */
|
||||
#undef HAVE_LIBPTHREAD
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
|
||||
+2
-1
@@ -5,7 +5,7 @@ dnl ******************************************************************
|
||||
dnl
|
||||
SPD_MAJOR_VERSION=0
|
||||
SPD_MINOR_VERSION=1
|
||||
SPD_MICRO_VERSION=1
|
||||
SPD_MICRO_VERSION=2
|
||||
SPD_VERSION=$SPD_MAJOR_VERSION.$SPD_MINOR_VERSION.$SPD_MICRO_VERSION
|
||||
|
||||
dnl *********************************************************************
|
||||
@@ -22,6 +22,7 @@ AC_PROG_LN_S
|
||||
|
||||
dnl Checks for libraries.
|
||||
AC_CHECK_LIB(osip, parser_init)
|
||||
AC_CHECK_LIB(pthread, pthread_create)
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
# DBCLASS_DNS 0x00000040 // DNS stuff
|
||||
# DBCLASS_NETTRAF 0x00000080 // network traffic
|
||||
# DBCLASS_CONFIG 0x00000100 // configuration
|
||||
debug_level = 0x0ffffffe
|
||||
# DBCLASS_RTP 0x00000200 // RTP proxy
|
||||
#
|
||||
debug_level = 0x000002fe
|
||||
|
||||
######################################################################
|
||||
# The IP addresses of the INBOUND and OUTBOUND interface can
|
||||
@@ -25,8 +27,8 @@ debug_level = 0x0ffffffe
|
||||
# or as dotted decimal IP:
|
||||
#
|
||||
# host_inbound=10.0.0.1
|
||||
|
||||
host_inbound = 192.168.1.8
|
||||
#
|
||||
host_inbound = 192.168.1.1
|
||||
host_outbound = ries.homeip.net
|
||||
|
||||
|
||||
@@ -34,11 +36,31 @@ host_outbound = ries.homeip.net
|
||||
# Port to listen for incomming SIP messages.
|
||||
# 5060 is usually the correct choise - don't change is unless you
|
||||
# know what you're doing
|
||||
|
||||
sip_port = 5060
|
||||
#
|
||||
sip_listen_port = 5060
|
||||
|
||||
|
||||
######################################################################
|
||||
# Shall we daemonize?
|
||||
#
|
||||
daemonize = 0
|
||||
|
||||
######################################################################
|
||||
# global switch to enable (1) or disable (0) the RTP proxy feature
|
||||
#
|
||||
rtp_proxy_enable = 1
|
||||
|
||||
######################################################################
|
||||
# Port range where to allocate listen ports for incomming RTP traffic
|
||||
# this should be a range that is not blocked by the firewall
|
||||
#
|
||||
rtp_port_low = 7070
|
||||
rtp_port_high = 7080
|
||||
|
||||
######################################################################
|
||||
# Timeout for RTP streams
|
||||
# after this number of seconds, at RTP stream is considered dead
|
||||
# and proxying it will be stopped.
|
||||
#
|
||||
rtp_timeout = 60
|
||||
|
||||
|
||||
+2
-2
@@ -19,11 +19,11 @@
|
||||
#
|
||||
|
||||
|
||||
CFLAGS =@CFLAGS@ -Wall -DBUILDSTR=\"`cat .buildno`\"
|
||||
CFLAGS =@CFLAGS@ -Wall -DBUILDSTR=\"`cat .buildno`\" -D_GNU_SOURCE
|
||||
|
||||
bin_PROGRAMS = siproxd
|
||||
siproxd_SOURCES = siproxd.c proxy.c register.c sock.c utils.c \
|
||||
log.c readconf.c
|
||||
log.c readconf.c rtpproxy.c
|
||||
|
||||
noinst_HEADERS = log.h siproxd.h
|
||||
|
||||
|
||||
+4
-4
@@ -85,10 +85,10 @@ MAKEINFO = @MAKEINFO@
|
||||
PACKAGE = @PACKAGE@
|
||||
VERSION = @VERSION@
|
||||
|
||||
CFLAGS = @CFLAGS@ -Wall -DBUILDSTR=\"`cat .buildno`\"
|
||||
CFLAGS = @CFLAGS@ -Wall -DBUILDSTR=\"`cat .buildno`\" -D_GNU_SOURCE
|
||||
|
||||
bin_PROGRAMS = siproxd
|
||||
siproxd_SOURCES = siproxd.c proxy.c register.c sock.c utils.c log.c readconf.c
|
||||
siproxd_SOURCES = siproxd.c proxy.c register.c sock.c utils.c log.c readconf.c rtpproxy.c
|
||||
|
||||
|
||||
noinst_HEADERS = log.h siproxd.h
|
||||
@@ -105,7 +105,7 @@ CPPFLAGS = @CPPFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
siproxd_OBJECTS = siproxd.o proxy.o register.o sock.o utils.o log.o \
|
||||
readconf.o
|
||||
readconf.o rtpproxy.o
|
||||
siproxd_LDADD = $(LDADD)
|
||||
siproxd_DEPENDENCIES =
|
||||
siproxd_LDFLAGS =
|
||||
@@ -122,7 +122,7 @@ DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
|
||||
TAR = gtar
|
||||
GZIP_ENV = --best
|
||||
DEP_FILES = .deps/log.P .deps/proxy.P .deps/readconf.P .deps/register.P \
|
||||
.deps/siproxd.P .deps/sock.P .deps/utils.P
|
||||
.deps/rtpproxy.P .deps/siproxd.P .deps/sock.P .deps/utils.P
|
||||
SOURCES = $(siproxd_SOURCES)
|
||||
OBJECTS = $(siproxd_OBJECTS)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define DBCLASS_DNS 0x00000040 // DNS stuff
|
||||
#define DBCLASS_NETTRAF 0x00000080 // network traffic
|
||||
#define DBCLASS_CONFIG 0x00000100 // configuration
|
||||
#define DBCLASS_RTP 0x00000200 // RTP proxy
|
||||
|
||||
|
||||
#define DEBUG(F...) log_debug(1,__FILE__, __LINE__,F)
|
||||
|
||||
+168
-48
@@ -29,6 +29,7 @@
|
||||
#include <netdb.h>
|
||||
|
||||
#include <osip/smsg.h>
|
||||
#include <osip/sdp.h>
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "log.h"
|
||||
@@ -45,9 +46,15 @@ extern struct siproxd_config configuration;
|
||||
*/
|
||||
|
||||
extern int errno;
|
||||
extern struct urlmap_s urlmap[]; // URL mapping table
|
||||
extern struct urlmap_s urlmap[]; /* URL mapping table */
|
||||
extern struct lcl_if_s local_addresses;
|
||||
extern int sip_socket; /* sending SIP datagrams */
|
||||
|
||||
|
||||
/*
|
||||
* PROXY_REQUEST
|
||||
*
|
||||
*/
|
||||
int proxy_request (sip_t *request) {
|
||||
int i;
|
||||
int sts;
|
||||
@@ -125,6 +132,13 @@ int proxy_request (sip_t *request) {
|
||||
|
||||
/* add my Via header line (inbound interface)*/
|
||||
sts = proxy_add_myvia(request, 1);
|
||||
|
||||
/* if this is CANCEL/BYE request, stop RTP proxying */
|
||||
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
|
||||
/* stop the RTP proxying stream */
|
||||
sts = rtp_stop_fwd(msg_getcall_id(request));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
/*
|
||||
@@ -138,6 +152,13 @@ int proxy_request (sip_t *request) {
|
||||
|
||||
/* add my Via header line (outbound interface)*/
|
||||
sts = proxy_add_myvia(request, 0);
|
||||
|
||||
/* if this is CANCEL/BYE request, stop RTP proxying */
|
||||
if (MSG_IS_BYE(request) || MSG_IS_CANCEL(request)) {
|
||||
/* stop the RTP proxying stream */
|
||||
sts = rtp_stop_fwd(msg_getcall_id(request));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -192,12 +213,16 @@ int proxy_request (sip_t *request) {
|
||||
port=configuration.sip_listen_port;
|
||||
}
|
||||
|
||||
sipsock_send_udp(addr, port, buffer, strlen(buffer));
|
||||
sipsock_send_udp(&sip_socket, addr, port, buffer, strlen(buffer), 1);
|
||||
free (buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PROXY_RESPONSE
|
||||
*
|
||||
*/
|
||||
int proxy_response (sip_t *response) {
|
||||
int i;
|
||||
int sts;
|
||||
@@ -271,7 +296,7 @@ int proxy_response (sip_t *response) {
|
||||
*/
|
||||
case RESTYP_INCOMMING:
|
||||
#if 0 /* do we really have to?? in the incomming response
|
||||
we have the correct address. But we mus rewrite an
|
||||
we have the correct address. But we must rewrite an
|
||||
outgoing response to an incomming INVITE request ! */
|
||||
/* If an 200 answer to an INVITE request, rewrite body */
|
||||
if ((MSG_IS_RESPONSEFOR(response,"INVITE") &&
|
||||
@@ -319,18 +344,15 @@ int proxy_response (sip_t *response) {
|
||||
port=configuration.sip_listen_port;
|
||||
}
|
||||
|
||||
sipsock_send_udp(addr, port, buffer, strlen(buffer));
|
||||
sipsock_send_udp(&sip_socket, addr, port, buffer, strlen(buffer), 1);
|
||||
free (buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* PROXY_GEN_RESPONSE
|
||||
*
|
||||
* send an proxy generated response back to the client.
|
||||
* Only errors are reported from the proxy itself.
|
||||
* code = SIP result code to deliver
|
||||
@@ -373,7 +395,8 @@ DEBUGC(DBCLASS_PROXY,"response=%p",response);
|
||||
}
|
||||
|
||||
/* send to destination */
|
||||
sipsock_send_udp(addr, atoi(via->port), buffer, strlen(buffer));
|
||||
sipsock_send_udp(&sip_socket, addr, atoi(via->port),
|
||||
buffer, strlen(buffer), 1);
|
||||
|
||||
/* free the resources */
|
||||
msg_free(response);
|
||||
@@ -384,10 +407,11 @@ DEBUGC(DBCLASS_PROXY,"response=%p",response);
|
||||
|
||||
|
||||
/*
|
||||
* routine to rewrite the header and message bodies
|
||||
* PROXY_ADD_MYVIA
|
||||
*
|
||||
*
|
||||
* interface == 0 -> outbound interface, else inbound interface
|
||||
*/
|
||||
|
||||
/* interface == 0 -> outbound interface, else inbound interface */
|
||||
int proxy_add_myvia (sip_t *request, int interface) {
|
||||
struct in_addr addr;
|
||||
char tmp[URL_STRING_SIZE];
|
||||
@@ -414,7 +438,10 @@ int proxy_add_myvia (sip_t *request, int interface) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* PROXY_DEL_MYVIA
|
||||
*
|
||||
*/
|
||||
int proxy_del_myvia (sip_t *response) {
|
||||
via_t *via;
|
||||
int sts;
|
||||
@@ -434,14 +461,19 @@ int proxy_del_myvia (sip_t *response) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* PROXY_REWRITE_INVITATION_BODY
|
||||
*
|
||||
*/
|
||||
int proxy_rewrite_invitation_body(sip_t *mymsg){
|
||||
body_t *body;
|
||||
struct in_addr addr;
|
||||
sdp_t *sdp;
|
||||
struct in_addr outb_addr, lcl_clnt_addr;
|
||||
int sts;
|
||||
char *oldbody;
|
||||
char newbody[BODY_MESSAGE_MAX_SIZE];
|
||||
char clen[8]; /* probably never more than 7 digits for content length !*/
|
||||
char clen[8]; /* content length: probably never more than 7 digits !*/
|
||||
int outb_rtp_port, inb_clnt_port;
|
||||
|
||||
sts = msg_getbody(mymsg, 0, &body);
|
||||
if (sts != 0) {
|
||||
@@ -451,7 +483,14 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){
|
||||
|
||||
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 1;
|
||||
}
|
||||
|
||||
{ /* just dump the buffer */
|
||||
char *tmp2;
|
||||
content_length_2char(mymsg->contentlength, &tmp2);
|
||||
DEBUG("Body before rewrite (clen=%s, strlen=%i):\n%s\n----",
|
||||
@@ -460,60 +499,141 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){
|
||||
}
|
||||
|
||||
|
||||
/* TODO */
|
||||
/* - change the 'c=' line to present the outbound address (the other
|
||||
side will send its audio data there
|
||||
- 'm=' line: here we should change the port number to a free local
|
||||
(outbound) port and set up an port forwarding to the hidden
|
||||
inbound client ...*/
|
||||
/*
|
||||
* RTP proxy: get ready and start forwarding
|
||||
*/
|
||||
sts = get_ip_by_host(sdp_c_addr_get(sdp,-1,0), &lcl_clnt_addr);
|
||||
sts = get_ip_by_host(configuration.outboundhost, &outb_addr);
|
||||
inb_clnt_port = atoi(sdp_m_port_get(sdp,0));
|
||||
/* start an RTP proxying stream */
|
||||
sts = rtp_start_fwd(msg_getcall_id(mymsg),
|
||||
outb_addr, &outb_rtp_port,
|
||||
lcl_clnt_addr, inb_clnt_port);
|
||||
|
||||
|
||||
/*
|
||||
* 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 incomming media port per session
|
||||
* is supported! I guess, there may be more allowed.
|
||||
*/
|
||||
{
|
||||
char *data=NULL;
|
||||
char *data2=NULL;
|
||||
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));
|
||||
|
||||
data = strstr (oldbody, "\nc=");
|
||||
if (data == NULL) data = strstr (oldbody, "\rc=");
|
||||
if (data == NULL) {
|
||||
/*
|
||||
* 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 1;
|
||||
}
|
||||
data += 3;
|
||||
|
||||
data_c += 3;
|
||||
/* can only rewrite IPV4 addresses by now */
|
||||
if (strncmp(data,"IN IP4 ",7)!=0) {
|
||||
if (strncmp(data_c,"IN IP4 ",7)!=0) {
|
||||
ERROR("c= does not contain an IN IP4 address");
|
||||
return 1;
|
||||
}
|
||||
data += 7;
|
||||
|
||||
data2 = strstr (data, "\n");
|
||||
if (data2 == NULL) data2 = strstr (oldbody, "\r");
|
||||
if (data2 == NULL) {
|
||||
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 1;
|
||||
}
|
||||
|
||||
/* copy up to the to-be-masqueraded address */
|
||||
memcpy(newbody, oldbody, data-oldbody);
|
||||
/*
|
||||
* 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 1;
|
||||
}
|
||||
data_m += 3;
|
||||
/* check for audio media */
|
||||
if (strncmp(data_m,"audio ",6)!=0) {
|
||||
ERROR("m= does not contain audio");
|
||||
return 1;
|
||||
}
|
||||
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 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* insert proxy outbound address */
|
||||
sts = get_ip_by_host(configuration.outboundhost, &addr);
|
||||
ptr=newbody+(data-oldbody);
|
||||
sprintf(ptr, "%s", inet_ntoa(addr));
|
||||
ptr += strlen(ptr);
|
||||
|
||||
/* copy rest */
|
||||
memcpy (ptr, data2, strlen(data2));
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -526,7 +646,7 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){
|
||||
sts = msg_setcontent_length(mymsg, clen);
|
||||
|
||||
|
||||
{
|
||||
{ /* just dump the buffer */
|
||||
char *tmp, *tmp2;
|
||||
sts = msg_getbody(mymsg, 0, &body);
|
||||
sts = body_2char(body, &tmp);
|
||||
|
||||
+10
-5
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -111,11 +112,15 @@ static int parse_config (FILE *configfile) {
|
||||
enum type {TYP_INT4, TYP_STRING, TYP_FLOAT} type;
|
||||
void *dest;
|
||||
} configoptions[] = {
|
||||
{ "debug_level", TYP_INT4, &configuration.debuglevel },
|
||||
{ "sip_port", TYP_INT4, &configuration.sip_listen_port },
|
||||
{ "daemonize", TYP_INT4, &configuration.daemonize },
|
||||
{ "host_inbound", TYP_STRING, &configuration.inboundhost },
|
||||
{ "host_outbound", TYP_STRING, &configuration.outboundhost },
|
||||
{ "debug_level", TYP_INT4, &configuration.debuglevel },
|
||||
{ "sip_listen_port", TYP_INT4, &configuration.sip_listen_port },
|
||||
{ "daemonize", TYP_INT4, &configuration.daemonize },
|
||||
{ "host_inbound", TYP_STRING, &configuration.inboundhost },
|
||||
{ "host_outbound", TYP_STRING, &configuration.outboundhost },
|
||||
{ "rtp_port_low", TYP_INT4, &configuration.rtp_port_low },
|
||||
{ "rtp_port_high", TYP_INT4, &configuration.rtp_port_high },
|
||||
{ "rtp_timeout", TYP_INT4, &configuration.rtp_timeout },
|
||||
{ "rtp_proxy_enable", TYP_INT4, &configuration.rtp_proxy_enable },
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
|
||||
+3
-2
@@ -39,7 +39,8 @@ static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
extern struct siproxd_config configuration;
|
||||
|
||||
extern int errno;
|
||||
struct urlmap_s urlmap[URLMAP_SIZE]; // URL mapping table
|
||||
struct urlmap_s urlmap[URLMAP_SIZE]; /* URL mapping table */
|
||||
extern int sip_socket; /* sending SIP datagrams */
|
||||
|
||||
/*
|
||||
* initialize the URL mapping table
|
||||
@@ -237,7 +238,7 @@ int register_response(sip_t *request, int flag) {
|
||||
port=configuration.sip_listen_port;
|
||||
}
|
||||
|
||||
sipsock_send_udp(addr, port, buffer, strlen(buffer));
|
||||
sipsock_send_udp(&sip_socket, addr, port, buffer, strlen(buffer), 1);
|
||||
|
||||
/* free the resources */
|
||||
msg_free(response);
|
||||
|
||||
@@ -40,6 +40,9 @@ static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
/* configuration storage */
|
||||
struct siproxd_config configuration;
|
||||
|
||||
/* socket used for sending SIP datagrams */
|
||||
int sip_socket=0;
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int sts;
|
||||
@@ -120,6 +123,9 @@ int main (int argc, char *argv[])
|
||||
/* listen for incomming messages */
|
||||
sipsock_listen();
|
||||
|
||||
/* initialize the RTP proxy thread */
|
||||
rtpproxy_init();
|
||||
|
||||
/* daemonize if requested to */
|
||||
if (configuration.daemonize) {
|
||||
DEBUGC(DBCLASS_CONFIG,"daemonizing");
|
||||
|
||||
+18
-2
@@ -24,7 +24,9 @@
|
||||
int sipsock_listen (void);
|
||||
int sipsock_wait(void);
|
||||
int sipsock_read(void *buf, size_t bufsize);
|
||||
int sipsock_send_udp(struct in_addr addr, int port, char *buffer, int size);
|
||||
int sipsock_send_udp(int *sock, struct in_addr addr, int port,
|
||||
char *buffer, int size, int allowdump);
|
||||
int sockbind(struct in_addr ipaddr, int localport);
|
||||
|
||||
/* register.c */
|
||||
void register_init(void);
|
||||
@@ -50,6 +52,13 @@ int compare_url(url_t *url1, url_t *url2);
|
||||
/* config.c */
|
||||
int read_config(char *name, int search);
|
||||
|
||||
/* rtpproxy.c */
|
||||
int rtpproxy_init( void );
|
||||
int rtp_start_fwd (call_id_t *callid,
|
||||
struct in_addr outbound_ipaddr, int *outboundport,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport);
|
||||
int rtp_stop_fwd (call_id_t *callid);
|
||||
|
||||
|
||||
/*
|
||||
* table to hold the client registrations
|
||||
@@ -72,6 +81,10 @@ struct siproxd_config {
|
||||
char *outboundhost;
|
||||
int sip_listen_port;
|
||||
int daemonize;
|
||||
int rtp_port_low;
|
||||
int rtp_port_high;
|
||||
int rtp_timeout;
|
||||
int rtp_proxy_enable;
|
||||
};
|
||||
|
||||
|
||||
@@ -80,8 +93,11 @@ struct siproxd_config {
|
||||
*/
|
||||
#define SIP_PORT 5060
|
||||
|
||||
#define URLMAP_SIZE 128 // size of URL mapping table
|
||||
#define URLMAP_SIZE 8 // number of URL mapping table entries
|
||||
#define RTPPROXY_SIZE 8 // number of rtp proxy entries
|
||||
|
||||
#define BUFFER_SIZE 1024 // input buffer for read from socket
|
||||
#define RTP_BUFFER_SIZE 512 // max size of an RTP frame
|
||||
#define URL_STRING_SIZE 128 // max size of an URL/URI string
|
||||
#define STATUSCODE_SIZE 5 // size of string representation of status
|
||||
#define DNS_CACHE_SIZE 32 // number of entries in internal DNS cache
|
||||
|
||||
+48
-26
@@ -53,24 +53,10 @@ static int listen_socket=0;
|
||||
* returns 0 on success
|
||||
*/
|
||||
int sipsock_listen (void) {
|
||||
struct sockaddr_in my_addr;
|
||||
int sts;
|
||||
struct in_addr ipaddr;
|
||||
|
||||
my_addr.sin_family = AF_INET;
|
||||
memset(&my_addr.sin_addr.s_addr, 0, sizeof(struct in_addr));
|
||||
my_addr.sin_port= htons(configuration.sip_listen_port);
|
||||
|
||||
listen_socket=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (listen_socket == 0) {
|
||||
ERROR("socket() call failed:%s",strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sts=bind(listen_socket, (struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (sts != 0) {
|
||||
ERROR("bind failed:%s",strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
memset(&ipaddr, 0, sizeof(struct in_addr));
|
||||
listen_socket=sockbind(ipaddr, configuration.sip_listen_port);
|
||||
|
||||
DEBUGC(DBCLASS_NET,"bound listen socket %i",listen_socket);
|
||||
return 0;
|
||||
@@ -106,29 +92,33 @@ int sipsock_read(void *buf, size_t bufsize) {
|
||||
/*
|
||||
* sends an UDP datagram to the specified destination
|
||||
*/
|
||||
int sipsock_send_udp(struct in_addr addr, int port, char *buffer, int size) {
|
||||
int sipsock_send_udp(int *sock, struct in_addr addr, int port,
|
||||
char *buffer, int size, int allowdump) {
|
||||
struct sockaddr_in dst_addr;
|
||||
static int s=0;
|
||||
int sts;
|
||||
|
||||
/* first time: allocate a socket for sending */
|
||||
if (s == 0) {
|
||||
s=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s == 0) {
|
||||
if (*sock == 0) {
|
||||
*sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (*sock == 0) {
|
||||
ERROR("socket() call failed:%s",strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
DEBUGC(DBCLASS_NET,"allocated send socket %i",s);
|
||||
DEBUGC(DBCLASS_NET,"allocated send socket %i",*sock);
|
||||
}
|
||||
|
||||
dst_addr.sin_family = AF_INET;
|
||||
memcpy(&dst_addr.sin_addr.s_addr, &addr, sizeof(struct in_addr));
|
||||
dst_addr.sin_port= htons(port);
|
||||
|
||||
DEBUGC(DBCLASS_NET,"send UDP packet to %s",inet_ntoa(addr));
|
||||
DUMP_BUFFER(DBCLASS_NETTRAF, buffer, size);
|
||||
|
||||
sts = sendto (s, buffer, size, 0, &dst_addr, sizeof(dst_addr));
|
||||
if (allowdump) {
|
||||
DEBUGC(DBCLASS_NET,"send UDP packet to %s:%i",
|
||||
inet_ntoa(addr),port);
|
||||
DUMP_BUFFER(DBCLASS_NETTRAF, buffer, size);
|
||||
}
|
||||
|
||||
sts = sendto (*sock, buffer, size, 0, &dst_addr, sizeof(dst_addr));
|
||||
|
||||
if (sts == -1) {
|
||||
ERROR("sendto() call failed:%s",strerror(errno));
|
||||
@@ -138,3 +128,35 @@ int sipsock_send_udp(struct in_addr addr, int port, char *buffer, int size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* generic routine to allocate and bind a socket to a specified
|
||||
* local address and port (UDP)
|
||||
*
|
||||
* returns socket number on success, zero on failure
|
||||
*/
|
||||
int sockbind(struct in_addr ipaddr, int localport) {
|
||||
struct sockaddr_in my_addr;
|
||||
int sts;
|
||||
int sock;
|
||||
|
||||
my_addr.sin_family = AF_INET;
|
||||
memcpy(&my_addr.sin_addr.s_addr, &ipaddr, sizeof(struct in_addr));
|
||||
my_addr.sin_port= htons(localport);
|
||||
|
||||
sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock == 0) {
|
||||
ERROR("socket() call failed:%s",strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
sts=bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr));
|
||||
if (sts != 0) {
|
||||
ERROR("bind failed:%s",strerror(errno));
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
+9
-1
@@ -113,6 +113,7 @@ int is_via_local (via_t *via) {
|
||||
struct in_addr addr_via, addr_myself;
|
||||
char *my_hostnames[]=
|
||||
{ configuration.inboundhost, configuration.outboundhost, NULL };
|
||||
int port;
|
||||
int i;
|
||||
char *ptr;
|
||||
|
||||
@@ -131,7 +132,11 @@ int is_via_local (via_t *via) {
|
||||
/* check the extracted VIA against my own host addresses */
|
||||
sts = get_ip_by_host(ptr, &addr_myself);
|
||||
|
||||
if (memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) {
|
||||
if (via->port) port=atoi(via->port);
|
||||
else port=SIP_PORT;
|
||||
|
||||
if ( (memcmp(&addr_myself, &addr_via, sizeof(addr_myself))==0) &&
|
||||
(port == configuration.sip_listen_port) ) {
|
||||
sts=1;
|
||||
break;
|
||||
}
|
||||
@@ -156,6 +161,8 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
||||
} dns_cache[DNS_CACHE_SIZE];
|
||||
static int cache_initialized=0;
|
||||
|
||||
if (hostname == NULL) return 1;
|
||||
|
||||
/* first time: initialize DNS cache */
|
||||
if (cache_initialized == 0) {
|
||||
DEBUGC(DBCLASS_DNS, "initializing DNS cache (%i entries)", DNS_CACHE_SIZE);
|
||||
@@ -166,6 +173,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
||||
time(&t);
|
||||
/* clean expired entries */
|
||||
for (i=0; i<DNS_CACHE_SIZE; i++) {
|
||||
if (dns_cache[i].hostname[0]=='\0') continue;
|
||||
if ( (dns_cache[i].timestamp+DNS_MAX_AGE) < t ) {
|
||||
DEBUGC(DBCLASS_DNS, "cleaning DNS cache, entry %i)", i);
|
||||
memset (&dns_cache[i], 0, sizeof(dns_cache[0]));
|
||||
|
||||
Reference in New Issue
Block a user