- removed IPCHAINS & IPTABLES (netfilter) proxy support
- RTPPROXY correction: match RTP ports crosswise - use one single port (and socket) on each side (inbound/ outbound) to send and receive RTP traffic for every active stream (patch by Christof Meerwald).
This commit is contained in:
parent
17d7438b5c
commit
fe9beb76d5
@ -4,8 +4,13 @@
|
||||
- better branch parameter calculation (via header),
|
||||
now honors RFC3261 for stateless proxies (section 16.11)
|
||||
- SIP request: remove a Route-header pointing to myself.
|
||||
This was an issue with Linphone 0.12.1. Thanks to
|
||||
Robert Högberg for a patch.
|
||||
This was an issue with Linphone 0.12.1.
|
||||
(patch by Robert Högberg).
|
||||
- removed IPCHAINS & IPTABLES (netfilter) proxy support
|
||||
- RTPPROXY correction: match RTP ports crosswise -
|
||||
use one single port (and socket) on each side (inbound/
|
||||
outbound) to send and receive RTP traffic for every
|
||||
active stream (patch by Christof Meerwald).
|
||||
22-Jan-2004: - ./configure option: --enable-static to build
|
||||
a completely statically linked executable
|
||||
- REGISTER honors the expires parameter
|
||||
|
||||
@ -84,11 +84,7 @@ registration_file = /var/lib/siproxd/siproxd_registrations
|
||||
# 0 - RTP proxy disabled
|
||||
# 1 - RTP proxy (UDP relay of siproxd)
|
||||
#
|
||||
# 2 - RTP masquerading IPCHAINS
|
||||
# 3 - RTP masquerading Netfilter/IPTABLES
|
||||
# (Siproxd will open masquerading tunnels
|
||||
# in the firewall. Requires ipchains.
|
||||
# NOTE: siproxd must be started by root!)
|
||||
# Note: IPCHAINS and IPTABLES(netfilter) support is no longer present!
|
||||
#
|
||||
rtp_proxy_enable = 1
|
||||
|
||||
|
||||
@ -24,9 +24,8 @@ CFLAGS =@CFLAGS@ -Wall -DBUILDSTR=\"`cat .buildno`\" -D_GNU_SOURCE
|
||||
sbin_PROGRAMS = siproxd
|
||||
siproxd_SOURCES = siproxd.c proxy.c register.c sock.c utils.c \
|
||||
sip_utils.c log.c readconf.c rtpproxy.c \
|
||||
rtpproxy_relay.c rtpproxy_masq.c accessctl.c \
|
||||
security.c auth.c \
|
||||
rtpproxy_mchains.c rtpproxy_mnetfltr.c
|
||||
rtpproxy_relay.c accessctl.c \
|
||||
security.c auth.c
|
||||
|
||||
noinst_HEADERS = log.h rewrite_rules.h siproxd.h digcalc.h rtpproxy.h
|
||||
|
||||
|
||||
@ -49,10 +49,6 @@ int rtpproxy_init( void ) {
|
||||
sts = STS_SUCCESS;
|
||||
} else if (configuration.rtp_proxy_enable == 1) { // Relay
|
||||
sts = rtp_relay_init ();
|
||||
} else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels (ipchains)
|
||||
sts = rtp_masq_init ();
|
||||
} else if (configuration.rtp_proxy_enable == 3) { // MASQ tunnels (netfilter)
|
||||
sts = rtp_masq_init ();
|
||||
} else {
|
||||
ERROR("CONFIG: rtp_proxy_enable has invalid value",
|
||||
configuration.rtp_proxy_enable);
|
||||
@ -80,14 +76,6 @@ int rtp_start_fwd (osip_call_id_t *callid, int direction,
|
||||
sts = rtp_relay_start_fwd (callid, direction, media_stream_no,
|
||||
outbound_ipaddr, outboundport,
|
||||
lcl_client_ipaddr, lcl_clientport);
|
||||
} else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels (ipchains)
|
||||
sts = rtp_masq_start_fwd (callid, direction, media_stream_no,
|
||||
outbound_ipaddr, outboundport,
|
||||
lcl_client_ipaddr, lcl_clientport);
|
||||
} else if (configuration.rtp_proxy_enable == 3) { // MASQ tunnels (netfilter)
|
||||
sts = rtp_masq_start_fwd (callid, direction, media_stream_no,
|
||||
outbound_ipaddr, outboundport,
|
||||
lcl_client_ipaddr, lcl_clientport);
|
||||
} else {
|
||||
ERROR("CONFIG: rtp_proxy_enable has invalid value",
|
||||
configuration.rtp_proxy_enable);
|
||||
@ -111,10 +99,6 @@ int rtp_stop_fwd (osip_call_id_t *callid, int direction) {
|
||||
sts = STS_SUCCESS;
|
||||
} else if (configuration.rtp_proxy_enable == 1) { // Relay
|
||||
sts = rtp_relay_stop_fwd(callid, direction, 0);
|
||||
} else if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels (ipchains)
|
||||
sts = rtp_masq_stop_fwd(callid, direction);
|
||||
} else if (configuration.rtp_proxy_enable == 3) { // MASQ tunnels (netfilter)
|
||||
sts = rtp_masq_stop_fwd(callid, direction);
|
||||
} else {
|
||||
ERROR("CONFIG: rtp_proxy_enable has invalid value",
|
||||
configuration.rtp_proxy_enable);
|
||||
|
||||
@ -22,7 +22,8 @@
|
||||
#define CALLIDHOST_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
int sock;
|
||||
int rtp_rx_sock; /* rx socket (0 -> free slot)*/
|
||||
int rtp_tx_sock; /* tx socket */
|
||||
char callid_number[CALLIDNUM_SIZE]; /* call ID */
|
||||
char callid_host[CALLIDHOST_SIZE]; /* --"-- */
|
||||
int direction; /* Direction of RTP stream */
|
||||
|
||||
@ -1,356 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2003 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osipparser2/osip_parser.h>
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "rtpproxy.h"
|
||||
#include "log.h"
|
||||
|
||||
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
BUILDSTR " $";
|
||||
|
||||
|
||||
/* configuration storage */
|
||||
extern struct siproxd_config configuration;
|
||||
|
||||
/* table to remember all active rtp proxy streams */
|
||||
extern rtp_proxytable_t rtp_proxytable[];
|
||||
|
||||
#if defined(HAVE_LINUX_IP_MASQ_H) || defined(HAVE_LINUX_NETFILTER_H)
|
||||
|
||||
/*
|
||||
* table to remember all active rtp proxy streams
|
||||
*/
|
||||
rtp_proxytable_t rtp_proxytable[RTPPROXY_SIZE];
|
||||
|
||||
|
||||
/************************************************************
|
||||
THIS HERE WILL ONLY WORK IF SIPROXD IS STARTED SUID ROOT !!
|
||||
However it is working when started root and then changed
|
||||
UID to eg. nobody - we'll just raise the privileged when
|
||||
we need to fiddle with the masquerading
|
||||
*************************************************************/
|
||||
|
||||
/*
|
||||
* initialize rtp_masq
|
||||
*
|
||||
* RETURNS
|
||||
* STS_SUCCESS on success
|
||||
*/
|
||||
int rtp_masq_init( void ) {
|
||||
|
||||
/* clean proxy table */
|
||||
memset (rtp_proxytable, 0, sizeof(rtp_proxytable));
|
||||
|
||||
if (configuration.rtp_proxy_enable == 2) { // MASQ tunnels (ipchains)
|
||||
#if !defined(HAVE_LINUX_IP_MASQ_H)
|
||||
ERROR("IPCHAINS support not built in");
|
||||
return STS_FAILURE;
|
||||
#endif
|
||||
} else if (configuration.rtp_proxy_enable == 3) { // MASQ tunnels (netfilter)
|
||||
#if !defined(HAVE_LINUX_NETFILTER_H)
|
||||
ERROR("NETFILTER/IPTABLES support not built in");
|
||||
return STS_FAILURE;
|
||||
#endif
|
||||
}
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int rtp_masq_start_fwd(osip_call_id_t *callid, int direction,
|
||||
int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outbound_lcl_port,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport) {
|
||||
int sts=STS_FAILURE;
|
||||
int i, j;
|
||||
int freeidx;
|
||||
time_t t;
|
||||
osip_call_id_t cid;
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_masq_start_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* life insurance: check size of received call_id strings
|
||||
* I don't know what the maximum allowed size within SIP is,
|
||||
* so if this test fails maybe it's just necessary to increase
|
||||
* the constants CALLIDNUM_SIZE and/or CALLIDHOST_SIZE.
|
||||
*/
|
||||
if (callid->number && strlen(callid->number) > CALLIDNUM_SIZE) {
|
||||
ERROR("rtp_masq_start_fwd: received callid number "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->number),CALLIDNUM_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
if (callid->host && strlen(callid->host) > CALLIDHOST_SIZE) {
|
||||
ERROR("rtp_masq_start_fwd: received callid host "
|
||||
"has too many characters (%i, max=%i)",
|
||||
strlen(callid->host),CALLIDHOST_SIZE);
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Age proxy table:
|
||||
* Just throw out expired (timed out) records. The proxy table
|
||||
* here for the MASQ module is only used to eliminate "doubles"
|
||||
* during INVITE/ACK. Later on, managing (aging & cleaning) the
|
||||
* masquerading tunnels is done by the kernel (IPMASQ).
|
||||
*/
|
||||
/*&&&&
|
||||
RACE CONDITIONS! A slot may be timed out, even if the actual
|
||||
masquerading tunnel is still active. A following new
|
||||
INVITE then tries to use the believed free port -> Buh
|
||||
- Can we poll (/proc/something) to figure out if the tunnel
|
||||
is still active before deleting? This would require knowledge
|
||||
of the text layout in /proc/xxx.
|
||||
- are there some other possibilities (netfilter/libiptc)?
|
||||
- introduce some kind of connection STATE to the proxy table.
|
||||
Timeout based discarding only is active for non-established.
|
||||
An INVITE would set the STATE to CONNECTING, the following
|
||||
ACK to CONNECTED. A CONNECTED entry can only be deleted by
|
||||
a BYE or CANCEL.
|
||||
- NETFILTER: during startup (RTP initialization) siproxd should
|
||||
clean left over entries that are within the RTP proxy port range
|
||||
*/
|
||||
time(&t);
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
if ((rtp_proxytable[i].sock != 0) &&
|
||||
((rtp_proxytable[i].timestamp+configuration.rtp_timeout)<t)) {
|
||||
/* this one has expired, delete it */
|
||||
cid.number = rtp_proxytable[i].callid_number;
|
||||
cid.host = rtp_proxytable[i].callid_host;
|
||||
rtp_masq_stop_fwd(&cid, rtp_proxytable[i].direction);
|
||||
DEBUGC(DBCLASS_RTP,"deleting expired proxy slot #%i %s@%s", i,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].callid_host);
|
||||
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: starting RTP proxy "
|
||||
"stream for: %s@%s (%s) #=%i",
|
||||
callid->number, callid->host,
|
||||
((direction == DIR_INCOMING) ? "incoming" : "outgoing"),
|
||||
media_stream_no);
|
||||
|
||||
/*
|
||||
* figure out, if this is an request to start an RTP proxy stream
|
||||
* that is already existing (identified by SIP Call-ID, direction and
|
||||
* media_stream_no). This can be due to UDP repetitions of the
|
||||
* INVITE request...
|
||||
*/
|
||||
freeidx=-1;
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
cid.number = rtp_proxytable[i].callid_number;
|
||||
cid.host = rtp_proxytable[i].callid_host;
|
||||
if (rtp_proxytable[i].sock != 0) {
|
||||
if((compare_callid(callid, &cid) == STS_SUCCESS) &&
|
||||
(rtp_proxytable[i].direction == direction) &&
|
||||
(rtp_proxytable[i].media_stream_no == media_stream_no)) {
|
||||
/* return the already known port number */
|
||||
*outbound_lcl_port=rtp_proxytable[i].outboundport;
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream already active (port=%i, "
|
||||
"id=%s, #=%i)", rtp_proxytable[i].outboundport,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].media_stream_no);
|
||||
return STS_SUCCESS;
|
||||
} /* compare */
|
||||
} else {
|
||||
/* remember the first free slot */
|
||||
if (freeidx < 0) freeidx=i;
|
||||
} /* if .sock */
|
||||
} /* for i */
|
||||
|
||||
/* rtp_proxytable port pool full? */
|
||||
if (freeidx == -1) {
|
||||
ERROR("rtp_masq_start_fwd: rtp_proxytable is full!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
/*
|
||||
* do loop over the range of available ports (7070-...) until able to
|
||||
* allocate a UDP tunnel with an even port number. If none can be found
|
||||
* available - Buh! return port=0
|
||||
*/
|
||||
for (i=configuration.rtp_port_low; i<=configuration.rtp_port_high; i+=2) {
|
||||
/* check if this port is already allocated in another stream.
|
||||
* IPCHAINS will print errors in SYSLOG when I try to use
|
||||
* the same port twice (IF it is still 'open' - no DST address
|
||||
* known yet) */
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: checking port %i",i);
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
if (rtp_proxytable[j].sock ==0) continue;
|
||||
if (rtp_proxytable[j].outboundport == i) {
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: port %i occupied",i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < RTPPROXY_SIZE) continue; /* try next port */
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: using port %i",i);
|
||||
|
||||
*outbound_lcl_port=i;
|
||||
|
||||
/* add masquerading entry */
|
||||
if (configuration.rtp_proxy_enable == 2) { // ipchains
|
||||
sts = rtp_mchains_create(lcl_client_ipaddr, lcl_clientport,
|
||||
outbound_ipaddr, *outbound_lcl_port);
|
||||
} else if (configuration.rtp_proxy_enable == 3) { // netfilter/iptables
|
||||
sts = rtp_mnetfltr_create(lcl_client_ipaddr, lcl_clientport,
|
||||
outbound_ipaddr, *outbound_lcl_port);
|
||||
}
|
||||
/* if success break, else try further on */
|
||||
if (sts == STS_SUCCESS) break;
|
||||
*outbound_lcl_port=0;
|
||||
} /* for i */
|
||||
|
||||
if (*outbound_lcl_port) {
|
||||
/* write entry into rtp_proxytable slot (freeidx) */
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: using proxy slot %i",freeidx);
|
||||
rtp_proxytable[freeidx].sock=1;
|
||||
|
||||
if (callid->number) {
|
||||
strcpy(rtp_proxytable[freeidx].callid_number, callid->number);
|
||||
} else {
|
||||
rtp_proxytable[freeidx].callid_number[0]='\0';
|
||||
}
|
||||
|
||||
if (callid->host) {
|
||||
strcpy(rtp_proxytable[freeidx].callid_host, callid->host);
|
||||
} else {
|
||||
rtp_proxytable[freeidx].callid_host[0]='\0';
|
||||
}
|
||||
|
||||
rtp_proxytable[freeidx].direction = direction;
|
||||
rtp_proxytable[freeidx].media_stream_no = media_stream_no;
|
||||
memcpy(&rtp_proxytable[freeidx].outbound_ipaddr,
|
||||
&outbound_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].outboundport=*outbound_lcl_port;
|
||||
memcpy(&rtp_proxytable[freeidx].inbound_client_ipaddr,
|
||||
&lcl_client_ipaddr, sizeof(struct in_addr));
|
||||
rtp_proxytable[freeidx].inbound_client_port=lcl_clientport;
|
||||
time(&rtp_proxytable[freeidx].timestamp);
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_start_fwd: masq address & port:%s:%i",
|
||||
utils_inet_ntoa(outbound_ipaddr),*outbound_lcl_port);
|
||||
return (*outbound_lcl_port)?STS_SUCCESS:STS_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
int rtp_masq_stop_fwd (osip_call_id_t *callid, int direction) {
|
||||
int sts=STS_FAILURE;
|
||||
int i;
|
||||
int got_match=0;
|
||||
osip_call_id_t cid;
|
||||
|
||||
/* let the UDP tunnel time-out */
|
||||
|
||||
if (callid == NULL) {
|
||||
ERROR("rtp_masq_stop_fwd: callid is NULL!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: stopping RTP proxy "
|
||||
"stream for: %s@%s (%s)",
|
||||
callid->number, callid->host,
|
||||
((direction == DIR_INCOMING) ? "incoming" : "outgoing"));
|
||||
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
cid.number = rtp_proxytable[i].callid_number;
|
||||
cid.host = rtp_proxytable[i].callid_host;
|
||||
|
||||
if (rtp_proxytable[i].sock &&
|
||||
(compare_callid(callid, &cid) == STS_SUCCESS) &&
|
||||
(rtp_proxytable[i].direction == direction)) {
|
||||
|
||||
/* remove masquerading entry */
|
||||
if (configuration.rtp_proxy_enable == 2) { // ipchains
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: stop RTP proxy slot %i "
|
||||
"(IPCHAINS)",i);
|
||||
sts = rtp_mchains_delete(
|
||||
rtp_proxytable[i].inbound_client_ipaddr,
|
||||
rtp_proxytable[i].inbound_client_port,
|
||||
rtp_proxytable[i].outbound_ipaddr,
|
||||
rtp_proxytable[i].outboundport);
|
||||
} else if (configuration.rtp_proxy_enable == 3) { // netfilter/iptables
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: stop RTP proxy slot %i "
|
||||
"(NETFILTER)",i);
|
||||
sts = rtp_mnetfltr_delete(
|
||||
rtp_proxytable[i].inbound_client_ipaddr,
|
||||
rtp_proxytable[i].inbound_client_port,
|
||||
rtp_proxytable[i].outbound_ipaddr,
|
||||
rtp_proxytable[i].outboundport);
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_masq_stop_fwd: cleaning proxy slot %i",i);
|
||||
memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0]));
|
||||
got_match=1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* did not find an active stream... */
|
||||
if (!got_match) {
|
||||
DEBUGC(DBCLASS_RTP,
|
||||
"rtp_masq_stop_fwd: can't find active stream for %s@%s (%s)",
|
||||
callid->number, callid->host,
|
||||
((direction == DIR_INCOMING) ? "incoming" : "outgoing"));
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
/*
|
||||
* don't have ipchains or iptables - dummy routines and complain
|
||||
*/
|
||||
|
||||
int rtp_masq_init( void ) {
|
||||
ERROR("Masquerading support is not enabled (compile time config option)");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
int rtp_masq_start_fwd(osip_call_id_t *callid, int direction,
|
||||
int media_stream_no,
|
||||
struct in_addr outbound_ipaddr, int *outbound_lcl_port,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport) {
|
||||
outbound_lcl_port=0;
|
||||
return STS_FAILURE;
|
||||
}
|
||||
int rtp_masq_stop_fwd (osip_call_id_t *callid, int direction) {
|
||||
return STS_FAILURE;
|
||||
}
|
||||
#endif
|
||||
@ -1,126 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2003 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#if defined(HAVE_LINUX_IP_MASQ_H)
|
||||
/* masq specific stuff */
|
||||
#include <asm/types.h> /* For __uXX types */
|
||||
#include <net/if.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <linux/ip_fw.h> /* For IP_FW_MASQ_CTL */
|
||||
#include <linux/ip_masq.h> /* For specific masq defs */
|
||||
#include <asm/param.h>
|
||||
#endif
|
||||
|
||||
#include <osipparser2/osip_parser.h>
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "rtpproxy.h"
|
||||
#include "log.h"
|
||||
|
||||
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
BUILDSTR " $";
|
||||
|
||||
|
||||
#if defined(HAVE_LINUX_IP_MASQ_H)
|
||||
/* socket for controlling the MASQ tunnels */
|
||||
static int masq_ctl_sock=0;
|
||||
|
||||
int rtp_mchains_create(struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
int uid,euid;
|
||||
int sts=STS_SUCCESS;
|
||||
struct ip_masq_ctl masq;
|
||||
|
||||
/* elevate privileges */
|
||||
uid=getuid();
|
||||
euid=geteuid();
|
||||
if (uid != euid) seteuid(0);
|
||||
|
||||
if (geteuid()!=0) {
|
||||
ERROR("create_listening_masq: must be running under UID root!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
if (masq_ctl_sock==0) {
|
||||
masq_ctl_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (masq_ctl_sock<0) {
|
||||
ERROR("create_listening_masq: allocating control socket() failed: %s",
|
||||
strerror(errno));
|
||||
sts = STS_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
memset (&masq, 0, sizeof (masq));
|
||||
|
||||
masq.m_target = IP_MASQ_TARGET_USER;
|
||||
masq.m_cmd = IP_MASQ_CMD_INSERT;
|
||||
masq.u.user.protocol= IPPROTO_UDP;
|
||||
|
||||
memcpy(&masq.u.user.saddr, &lcl_addr, sizeof(lcl_addr));
|
||||
masq.u.user.sport = htons(lcl_port);
|
||||
|
||||
memcpy(&masq.u.user.maddr, &msq_addr, sizeof(msq_addr));
|
||||
masq.u.user.mport = htons(msq_port);
|
||||
|
||||
if (setsockopt(masq_ctl_sock, IPPROTO_IP,
|
||||
IP_FW_MASQ_CTL, (char *)&masq, sizeof(masq))) {
|
||||
DEBUGC(DBCLASS_RTP, "create_listening_masq: setsockopt() failed: %s",
|
||||
strerror(errno));
|
||||
sts = STS_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
exit:
|
||||
/* drop privileges */
|
||||
if (uid != euid) seteuid(euid);
|
||||
return sts;
|
||||
}
|
||||
|
||||
#else
|
||||
/*
|
||||
* don't have ipchains - dummy routines and complain
|
||||
*/
|
||||
|
||||
int rtp_mchains_create(struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
ERROR("IPCHAINS support is not enabled (compile time config option)");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
int rtp_mchains_delete (struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
/* nothing to do here, just let the tunnel time out */
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
@ -1,145 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2003 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 <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#if defined(HAVE_LINUX_NETFILTER_H)
|
||||
/* iptables/netfilter specific stuff */
|
||||
//&&&&
|
||||
#endif
|
||||
|
||||
#include <osipparser2/osip_parser.h>
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "rtpproxy.h"
|
||||
#include "log.h"
|
||||
|
||||
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
BUILDSTR " $";
|
||||
|
||||
|
||||
#if defined(HAVE_LINUX_NETFILTER_H)
|
||||
|
||||
static char *ipchains_exe="/sbin/iptables";
|
||||
static char *add_rule =
|
||||
"%s -t nat -A PREROUTING -p udp --destination-port %i -j DNAT "
|
||||
"--to-destination %s:%i";
|
||||
static char *del_rule =
|
||||
"%s -t nat -D PREROUTING -p udp --destination-port %i -j DNAT "
|
||||
"--to-destination %s:%i";
|
||||
|
||||
/*
|
||||
* lcl_addr IP of local UA
|
||||
* lcl_port port of local UA
|
||||
* msq_addr masqueraded address (public IP of proxy)
|
||||
* msq_port masqueraded port (where siproxd wants to receive RTP traffic)
|
||||
*/
|
||||
int rtp_mnetfltr_create (struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
int uid,euid;
|
||||
int sts;
|
||||
char tmp[256];
|
||||
|
||||
INFO("rtp_mchains_create");
|
||||
|
||||
/* Still an Hack I don't like - use a system() call to alter the FW */
|
||||
sprintf(tmp, add_rule, ipchains_exe, msq_port, utils_inet_ntoa(lcl_addr),
|
||||
lcl_port);
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_mnetfltr_create: add FW rule:[%s]",tmp);
|
||||
|
||||
/* elevate privileges */
|
||||
uid=getuid();
|
||||
euid=geteuid();
|
||||
if (uid != euid) seteuid(0);
|
||||
|
||||
if (geteuid()!=0) {
|
||||
ERROR("create_listening_masq: must be running under UID root!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
sts = system(tmp);
|
||||
if (sts <0) {
|
||||
ERROR("rtp_mnetfltr_create: system() failed with sts=%i", sts);
|
||||
}
|
||||
|
||||
/* drop privileges */
|
||||
if (uid != euid) seteuid(euid);
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
|
||||
int rtp_mnetfltr_delete (struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
int uid,euid;
|
||||
int sts;
|
||||
char tmp[256];
|
||||
|
||||
INFO("rtp_mchains_delete");
|
||||
|
||||
/* Still an Hack I don't like - use a system() call to alter the FW */
|
||||
sprintf(tmp, del_rule, ipchains_exe, msq_port, utils_inet_ntoa(lcl_addr),
|
||||
lcl_port);
|
||||
|
||||
DEBUGC(DBCLASS_RTP,"rtp_mnetfltr_delete: del FW rule:[%s]",tmp);
|
||||
|
||||
/* elevate privileges */
|
||||
uid=getuid();
|
||||
euid=geteuid();
|
||||
if (uid != euid) seteuid(0);
|
||||
|
||||
if (geteuid()!=0) {
|
||||
ERROR("create_listening_masq: must be running under UID root!");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
sts = system(tmp);
|
||||
if (sts <0) {
|
||||
ERROR("rtp_mnetfltr_create: system() failed with sts=%i", sts);
|
||||
}
|
||||
|
||||
/* drop privileges */
|
||||
if (uid != euid) seteuid(euid);
|
||||
return STS_SUCCESS;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* don't have iptables - dummy routines and complain
|
||||
*/
|
||||
|
||||
int rtp_mnetfltr_create (struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
ERROR("NETFILTER support is not enabled (compile time config option)");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
|
||||
int rtp_mnetfltr_delete (struct in_addr lcl_addr, int lcl_port,
|
||||
struct in_addr msq_addr, int msq_port) {
|
||||
ERROR("NETFILTER support is not enabled (compile time config option)");
|
||||
return STS_FAILURE;
|
||||
}
|
||||
#endif
|
||||
@ -113,7 +113,7 @@ static void *rtpproxy_main(void *arg) {
|
||||
int i, sts;
|
||||
int num_fd;
|
||||
osip_call_id_t callid;
|
||||
static int rtp_socket=0;
|
||||
//&&&& static int rtp_socket=0;
|
||||
static char rtp_buff[RTP_BUFFER_SIZE];
|
||||
int count;
|
||||
|
||||
@ -149,22 +149,54 @@ static void *rtpproxy_main(void *arg) {
|
||||
|
||||
/* check for data available and send to destination */
|
||||
for (i=0;(i<RTPPROXY_SIZE) && (num_fd>0);i++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
FD_ISSET(rtp_proxytable[i].sock, &fdset) ) {
|
||||
if ( (rtp_proxytable[i].rtp_rx_sock != 0) &&
|
||||
FD_ISSET(rtp_proxytable[i].rtp_rx_sock, &fdset) ) {
|
||||
/* yup, have some data to send */
|
||||
|
||||
/* read from sock rtp_proxytable[i].sock*/
|
||||
count=read(rtp_proxytable[i].sock, rtp_buff, RTP_BUFFER_SIZE);
|
||||
count=read(rtp_proxytable[i].rtp_rx_sock, rtp_buff, RTP_BUFFER_SIZE);
|
||||
|
||||
if (count<0) {
|
||||
WARN("read() returned error [%s]",strerror(errno));
|
||||
}
|
||||
|
||||
/* write to dest via socket rtp__socket */
|
||||
sts = sipsock_send_udp(&rtp_socket,
|
||||
rtp_proxytable[i].inbound_client_ipaddr,
|
||||
rtp_proxytable[i].inbound_client_port,
|
||||
rtp_buff, count, 0); /* don't dump it */
|
||||
//&&&& /* write to dest via socket rtp__socket */
|
||||
//&&&& sts = sipsock_send_udp(&rtp_socket,
|
||||
//&&&& rtp_proxytable[i].inbound_client_ipaddr,
|
||||
//&&&& rtp_proxytable[i].inbound_client_port,
|
||||
//&&&& rtp_buff, count, 0); /* don't dump it */
|
||||
if (rtp_proxytable[i].rtp_tx_sock == 0)
|
||||
{
|
||||
int j;
|
||||
osip_call_id_t callid;
|
||||
int direction = rtp_proxytable[i].direction;
|
||||
int media_stream_no = rtp_proxytable[i].media_stream_no;
|
||||
|
||||
callid.number = rtp_proxytable[i].callid_number;
|
||||
callid.host = rtp_proxytable[i].callid_host;
|
||||
|
||||
for (j=0;(j<RTPPROXY_SIZE);j++) {
|
||||
osip_call_id_t cid;
|
||||
|
||||
cid.number = rtp_proxytable[j].callid_number;
|
||||
cid.host = rtp_proxytable[j].callid_host;
|
||||
|
||||
if ( (rtp_proxytable[j].rtp_rx_sock != 0) &&
|
||||
(direction != rtp_proxytable[j].direction) &&
|
||||
(media_stream_no == rtp_proxytable[j].media_stream_no) &&
|
||||
(compare_callid(&callid, &cid) == STS_SUCCESS) ) {
|
||||
rtp_proxytable[i].rtp_tx_sock = rtp_proxytable[j].rtp_rx_sock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rtp_proxytable[i].rtp_tx_sock != 0) {
|
||||
/* write to dest via socket rtp_tx_sock */
|
||||
sts = sipsock_send_udp(&rtp_proxytable[i].rtp_tx_sock,
|
||||
rtp_proxytable[i].inbound_client_ipaddr,
|
||||
rtp_proxytable[i].inbound_client_port,
|
||||
rtp_buff, count, 0); /* don't dump it */
|
||||
}
|
||||
|
||||
/* update timestamp of last usage */
|
||||
rtp_proxytable[i].timestamp=t;
|
||||
@ -179,13 +211,15 @@ static void *rtpproxy_main(void *arg) {
|
||||
if (t > (last_t+10) ) {
|
||||
last_t = t;
|
||||
for (i=0;i<RTPPROXY_SIZE; i++) {
|
||||
if ( (rtp_proxytable[i].sock != 0) &&
|
||||
if ( (rtp_proxytable[i].rtp_rx_sock != 0) &&
|
||||
((rtp_proxytable[i].timestamp+configuration.rtp_timeout)<t)) {
|
||||
/* this one has expired, clean it up */
|
||||
callid.number=rtp_proxytable[i].callid_number;
|
||||
callid.host=rtp_proxytable[i].callid_host;
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream sock=%i %s@%s (idx=%i) "
|
||||
"has expired", rtp_proxytable[i].sock,
|
||||
DEBUGC(DBCLASS_RTP,"RTP stream rx_sock=%i tx_sock=%i "
|
||||
"%s@%s (idx=%i) has expired",
|
||||
rtp_proxytable[i].rtp_rx_sock,
|
||||
rtp_proxytable[i].rtp_tx_sock,
|
||||
callid.number, callid.host, i);
|
||||
/* don't lock the mutex, as we own the lock already here */
|
||||
rtp_relay_stop_fwd(&callid, rtp_proxytable[i].direction, 1);
|
||||
@ -276,7 +310,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int direction,
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
cid.number = rtp_proxytable[i].callid_number;
|
||||
cid.host = rtp_proxytable[i].callid_host;
|
||||
if (rtp_proxytable[i].sock &&
|
||||
if (rtp_proxytable[i].rtp_rx_sock &&
|
||||
(compare_callid(callid, &cid) == STS_SUCCESS) &&
|
||||
(rtp_proxytable[i].direction == direction) &&
|
||||
(rtp_proxytable[i].media_stream_no == media_stream_no) ) {
|
||||
@ -307,7 +341,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int direction,
|
||||
*/
|
||||
freeidx=-1;
|
||||
for (j=0; j<RTPPROXY_SIZE; j++) {
|
||||
if (rtp_proxytable[j].sock==0) {
|
||||
if (rtp_proxytable[j].rtp_rx_sock==0) {
|
||||
freeidx=j;
|
||||
break;
|
||||
}
|
||||
@ -356,7 +390,7 @@ int rtp_relay_start_fwd (osip_call_id_t *callid, int direction,
|
||||
}
|
||||
|
||||
/* write entry into rtp_proxytable slot (freeidx) */
|
||||
rtp_proxytable[freeidx].sock=sock;
|
||||
rtp_proxytable[freeidx].rtp_rx_sock=sock;
|
||||
|
||||
if (callid->number) {
|
||||
strcpy(rtp_proxytable[freeidx].callid_number, callid->number);
|
||||
@ -456,19 +490,19 @@ int rtp_relay_stop_fwd (osip_call_id_t *callid, int direction,
|
||||
for (i=0; i<RTPPROXY_SIZE; i++) {
|
||||
cid.number = rtp_proxytable[i].callid_number;
|
||||
cid.host = rtp_proxytable[i].callid_host;
|
||||
if (rtp_proxytable[i].sock &&
|
||||
if (rtp_proxytable[i].rtp_rx_sock &&
|
||||
(compare_callid(callid, &cid) == STS_SUCCESS) &&
|
||||
(rtp_proxytable[i].direction == direction)) {
|
||||
sts = close(rtp_proxytable[i].sock);
|
||||
sts = close(rtp_proxytable[i].rtp_rx_sock);
|
||||
DEBUGC(DBCLASS_RTP,"closed socket %i for RTP stream "
|
||||
"%s:%s == %s:%s (idx=%i) sts=%i",
|
||||
rtp_proxytable[i].sock,
|
||||
rtp_proxytable[i].rtp_rx_sock,
|
||||
rtp_proxytable[i].callid_number,
|
||||
rtp_proxytable[i].callid_host,
|
||||
callid->number, callid->host, i, sts);
|
||||
if (sts < 0) {
|
||||
ERROR("Error in close(%i): %s nolock=%i %s:%s\n",
|
||||
rtp_proxytable[i].sock,
|
||||
rtp_proxytable[i].rtp_rx_sock,
|
||||
strerror(errno), nolock,
|
||||
callid->number, callid->host);
|
||||
}
|
||||
@ -521,10 +555,10 @@ static int rtp_recreate_fdset(void) {
|
||||
FD_ZERO(&master_fdset);
|
||||
master_fd_max=-1;
|
||||
for (i=0;i<RTPPROXY_SIZE;i++) {
|
||||
if (rtp_proxytable[i].sock != 0) {
|
||||
FD_SET(rtp_proxytable[i].sock, &master_fdset);
|
||||
if (rtp_proxytable[i].sock > master_fd_max) {
|
||||
master_fd_max=rtp_proxytable[i].sock;
|
||||
if (rtp_proxytable[i].rtp_rx_sock != 0) {
|
||||
FD_SET(rtp_proxytable[i].rtp_rx_sock, &master_fdset);
|
||||
if (rtp_proxytable[i].rtp_rx_sock > master_fd_max) {
|
||||
master_fd_max=rtp_proxytable[i].rtp_rx_sock;
|
||||
}
|
||||
}
|
||||
} /* for i */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user