Release 0.2.1
This commit is contained in:
parent
b31f9c7b86
commit
d9173e19b6
@ -1,3 +1,12 @@
|
||||
0.2.1
|
||||
=====
|
||||
- 28-Sep-2002: - Released version 0.2.1
|
||||
- 27-Sep-2002: - first implementation of proxy authentication (for REGISTER)
|
||||
- 24-Sep-2002: - if daemonized, log to syslog
|
||||
- 22-Sep-2002: - added access list support for registration and incomming
|
||||
SIP packets.
|
||||
- 21-Sep-2002: - added RPM support (Spec File)
|
||||
|
||||
0.2.0
|
||||
=====
|
||||
- 17-Sep-2002: - Released version 0.2.0
|
||||
|
||||
@ -21,4 +21,4 @@
|
||||
|
||||
SUBDIRS = src doc scripts
|
||||
|
||||
EXTRA_DIST = TODO RELNOTES
|
||||
EXTRA_DIST = TODO RELNOTES siproxd.spec
|
||||
|
||||
7
README
7
README
@ -130,7 +130,7 @@ IMPORTANT NOTICE
|
||||
The gethostbyname() function leaks memory in glibc 2.1.1 (-> RedHat 6.0).
|
||||
The quick fix is to delete the nisplus service from hosts entry in
|
||||
/etc/nsswitch.conf.
|
||||
In my tests, memory use remained stable after I made the mentioned change.
|
||||
In my tests, memory usage remained stable after I made the mentioned change.
|
||||
|
||||
(source: http://www.squid-cache.org/Doc/FAQ/FAQ-14.html)
|
||||
|
||||
@ -145,7 +145,7 @@ Please feel free to contact the author to:
|
||||
|
||||
and visit the website at http://siproxd.sourceforge.net/
|
||||
|
||||
There also is a siproxd mailinglist available on sourceforge.
|
||||
There is a siproxd mailinglist available on sourceforge.
|
||||
|
||||
Thomas Ries (tries@gmx.net)
|
||||
GnuPG Public Key:
|
||||
@ -160,3 +160,6 @@ CREDITS
|
||||
Thanks to sourceforge.net for providing the distribution platform and
|
||||
infrastructure.
|
||||
|
||||
Also credits to the maintainers of linphone from where I have taken some
|
||||
code parts for MD5 proxy authentication.
|
||||
|
||||
|
||||
23
RELNOTES
23
RELNOTES
@ -1,18 +1,29 @@
|
||||
Release Notes for siproxd-0.2.1
|
||||
===============================
|
||||
TO BE ADAPTED!!
|
||||
- SIP Proxy for SIP based softphones hidden behind a masquerading firewall
|
||||
- Includes an RTP data stream proxy for incomming audio data
|
||||
- Includes an RTP data stream proxy for *incomming* audio data
|
||||
(outgoing RTP data should be handled by IP masquerading by the firewall)
|
||||
- Port range to be used for incomming RTP traffic is configurable
|
||||
(-> easy to set up apropriate firewall rules for incomming traffic)
|
||||
- Multiple local users/hosts can be masqueraded simultaneously
|
||||
- Supports running in a chroot jail (configurable)
|
||||
- Supports changing user ID after startup (if started as root)
|
||||
- All configuration done via config file
|
||||
- Supports changing user-ID after startup (if started as root)
|
||||
- All configuration done via one simple ascii configuration file
|
||||
- Proxy Authentication for registration of local clients (User Agents)
|
||||
- Logging to syslog in Daemon mode
|
||||
- Access control (IP based) for incomming traffic
|
||||
- RPM support (spec file)
|
||||
|
||||
Requirements:
|
||||
- pthreads
|
||||
- libosip 0.8.8
|
||||
|
||||
- currently tested on Linux 2.2.x (Redhat 6.0) and 2.4.x (Redhat 7.2)
|
||||
however, should run on any other
|
||||
Currently tested on Linux 2.2.x (Redhat 6.0) and 2.4.x (Redhat 7.2),
|
||||
should run on others Linux distributions as well.
|
||||
|
||||
Interoperability (tested with softphones):
|
||||
- Linphone (http://www.linphone.org)
|
||||
- Kphone (http://www.wirlab.net/kphone/)
|
||||
|
||||
-----
|
||||
md5sum for siproxd-0.2.1.tar.gz:
|
||||
|
||||
14
TODO
14
TODO
@ -1,20 +1,22 @@
|
||||
TODOs, in random order:
|
||||
=======================
|
||||
|
||||
- re-think the registration mechanism (mapping and decision criteria
|
||||
for in- and outgoing stuff...
|
||||
- client authentication for registration - multiple user feature
|
||||
|
||||
- logging via syslog if running in daemon mode
|
||||
- redo return status (make then at least DEFINED constants)
|
||||
|
||||
- get_ip_by_host: reduce DNS timeouts
|
||||
- Documentation (yeah, yeah...)
|
||||
|
||||
- Documentation
|
||||
- general security issues
|
||||
|
||||
- automagically create a proper config file during install
|
||||
|
||||
- client authentication
|
||||
- get_ip_by_host: reduce DNS timeouts
|
||||
|
||||
- support for "full duplex" RTP proxying
|
||||
|
||||
- portability to other platforms / operating systems
|
||||
first goal: other Unixes
|
||||
|
||||
|
||||
|
||||
|
||||
@ -87,9 +87,15 @@
|
||||
/* Define if you have the strstr function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define if you have the syslog function. */
|
||||
#undef HAVE_SYSLOG
|
||||
|
||||
/* Define if you have the vfprintf function. */
|
||||
#undef HAVE_VFPRINTF
|
||||
|
||||
/* Define if you have the vsnprintf function. */
|
||||
#undef HAVE_VSNPRINTF
|
||||
|
||||
/* Define if you have the <errno.h> header file. */
|
||||
#undef HAVE_ERRNO_H
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ dnl ******************************************************************
|
||||
dnl
|
||||
SPD_MAJOR_VERSION=0
|
||||
SPD_MINOR_VERSION=2
|
||||
SPD_MICRO_VERSION=0
|
||||
SPD_MICRO_VERSION=1
|
||||
SPD_VERSION=$SPD_MAJOR_VERSION.$SPD_MINOR_VERSION.$SPD_MICRO_VERSION
|
||||
|
||||
dnl *********************************************************************
|
||||
@ -51,10 +51,11 @@ AC_FUNC_MEMCMP
|
||||
AC_FUNC_VPRINTF
|
||||
AC_CHECK_FUNCS(strerror)
|
||||
AC_CHECK_FUNCS(gethostbyname)
|
||||
AC_CHECK_FUNCS(getopt_long_only daemon)
|
||||
AC_CHECK_FUNCS(getopt_long_only daemon syslog)
|
||||
AC_CHECK_FUNCS(getuid setuid getgid setgid getpwnam chroot)
|
||||
AC_CHECK_FUNCS(socket bind select read send sendto)
|
||||
AC_CHECK_FUNCS(strncpy strchr strstr sprintf vfprintf fgets sscanf)
|
||||
AC_CHECK_FUNCS(strncpy strchr strstr sprintf vfprintf vsnprintf)
|
||||
AC_CHECK_FUNCS(fgets sscanf)
|
||||
|
||||
|
||||
AC_OUTPUT(Makefile \
|
||||
|
||||
116
doc/FAQ
Normal file
116
doc/FAQ
Normal file
@ -0,0 +1,116 @@
|
||||
|
||||
|
||||
Still under construction...
|
||||
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Q: What softphone work with siproxd?
|
||||
|
||||
A: The goal is that every softphone (that is SIP compliant) should be
|
||||
able to work via siproxd. Tested and/or reported to work so far:
|
||||
- linphone (0.9.0)
|
||||
- kphone (1.0.2)
|
||||
---------------------------------------------------------------------------
|
||||
Q: Siproxd's RTP proxying does only work for incomming RTP audio data.
|
||||
Should it not also proxy outgoing RTP data?
|
||||
|
||||
A: Curently (0.2.0) that is the correct behaviour. Incomming RTP traffic
|
||||
is handled by siproxd's RTP proxy. However, outgoing RTP traffic has
|
||||
to be handled by the firewall (IP masquerading).
|
||||
---------------------------------------------------------------------------
|
||||
Q: How do I setup IP masquerading for the outgoing RTP traffic?
|
||||
|
||||
A: if you are using 'ipchains' it is a firewall rule like the following:
|
||||
|
||||
# ipchains -A forward -i ppp0 -j MASQ -s 10.0.0.0/24 -d 0.0.0.0/0
|
||||
|
||||
This will set up IP masquerading for all local hostx (10.x.x.x) to
|
||||
the Internet (connected on ppp0). Read the ipchains documentation
|
||||
for details.
|
||||
More recent Linux Kernels (2.4.x) may use 'iptables' instead of
|
||||
'ipchains'. Check the corresponding documentation for details
|
||||
how to configure IP masquerading there.
|
||||
---------------------------------------------------------------------------
|
||||
Q: Is it possible from a remote computer to call the inbound computer?
|
||||
|
||||
A: Yes, see also next question.
|
||||
---------------------------------------------------------------------------
|
||||
Q: What SIP address must the remote computer use to make a call?
|
||||
|
||||
A: Scenario
|
||||
--------
|
||||
|
||||
private IP address range : Internet
|
||||
10.0.0.x : (publich IP address range)
|
||||
:
|
||||
: foo.bar.org xxx.org
|
||||
+-------------+ +--------------+ +-------------+
|
||||
! !.10 .1 ! masquerading ! publicIP ! !
|
||||
! IntHost !-------------! Firewall !------------>>! externalHost!
|
||||
! ! eth0! !ppp0 ! !
|
||||
+-------------+ +--------------+ +-------------+
|
||||
user: johndoe user: test
|
||||
|
||||
- IntHost is running an SIP softphone (like linphone, kphone)
|
||||
|
||||
- The SIP address used by IntHost is sip:johndoe@foo.bar.org
|
||||
|
||||
- The softphone on IntHost is configured to register at siproxd
|
||||
running on the firewall host (10.0.0.1) as sip:johndoe@foo.bar.org
|
||||
|
||||
- foo.bar.org is the domain name corresponding to the public IP address
|
||||
of the firewall (eg use some dynamic DNS service [1])
|
||||
|
||||
- externalHost does *not* register at siproxd running on the firewall host.
|
||||
|
||||
|
||||
The relevant part of the configuration (linphone) of IntHost
|
||||
then looks like ($HOME/gnome/linphone):
|
||||
|
||||
[sip]
|
||||
sip_port=5060
|
||||
use_registrar=1
|
||||
username=johndoe
|
||||
hostname=foo.bar.org
|
||||
registrar=sip:10.0.0.1
|
||||
reg_passwd=
|
||||
addr_of_rec=sip:johndoe@foo.bar.org
|
||||
reg_expires=900
|
||||
as_proxy=1
|
||||
as_redirect=0
|
||||
as_outbound=1
|
||||
|
||||
To make an outgoing call from IntHost simply use the SIP address of the
|
||||
target ( -> sip:test@xxx.org).
|
||||
|
||||
test@xxx.org can make a incomming calls - it simply has to use the registered
|
||||
SIP address of the softphone running on IntHost (sip:johndoe@foo.bar.org).
|
||||
Siproxd will then rewrite and forward the incomming request to Inthost.
|
||||
|
||||
The externalHost does not need to know anything about the proxy. For the
|
||||
user sip:test@xxx.org it looks as he directly sends the traffic to
|
||||
foo.bar.org, siproxd then takes care about where to send it from there.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Q: How does the registration and mapping of inbound clients work?
|
||||
|
||||
A: The mapping mechanism of SIP addresses works basically like:
|
||||
|
||||
Inthost sends a registration to siproxd with:
|
||||
- a 'To:' address of the address to be registered (sip:johndoe@foo.bar.org)
|
||||
(lets call this address the 'masqueraded' or 'public' address)
|
||||
|
||||
- a 'Contact:' address of the *true* address (sip:johndoe@10.0.0.10)
|
||||
|
||||
Siproxd then will basically 'just' substitute the true address by the
|
||||
masqueraded address and vice versa. That means you can have multiple
|
||||
IntHosts (each of them using a different user name) running at the
|
||||
same time.
|
||||
|
||||
For an incomming call, siproxd will search its registration table for
|
||||
the requested SIP address and so finds the internal host that belong to it.
|
||||
|
||||
This of course *requires* that the username part of the SIP address is
|
||||
unique for each softphone that registers a the proxy (So this is more or
|
||||
less the mechanism that you mentioned in your mail).
|
||||
---------------------------------------------------------------------------
|
||||
@ -19,4 +19,4 @@
|
||||
#
|
||||
|
||||
|
||||
EXTRA_DIST = siproxd.conf.example
|
||||
EXTRA_DIST = siproxd.conf.example FAQ
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
#
|
||||
# !! This is a sample file, adapt it to your needs before using it
|
||||
#
|
||||
# !! Strings MUST NOT contain spaces in between !!
|
||||
#
|
||||
|
||||
######################################################################
|
||||
# The IP addresses of the INBOUND and OUTBOUND interface can
|
||||
@ -12,14 +14,36 @@
|
||||
#
|
||||
# or as dotted decimal IP:
|
||||
#
|
||||
# host_inbound=10.0.0.1
|
||||
#
|
||||
host_inbound = 192.168.1.1
|
||||
host_outbound = ries.homeip.net
|
||||
host_inbound = 10.0.0.1
|
||||
host_outbound = my.external-ip.address
|
||||
|
||||
|
||||
######################################################################
|
||||
# Port to listen for incomming SIP messages.
|
||||
# Access lists in the form: IP/mask (ex. 10.0.0.1/24)
|
||||
# multiple entries may be separated by commas NO SPACES ARE ALLOWED!!
|
||||
# Empty list means 'does not apply' - no filtering is done then.
|
||||
# For *allow* lists this means: always allow, for *deny* lists that
|
||||
# this means never deny.
|
||||
#
|
||||
# hosts_allow_reg: defines nets where we accept registrations from
|
||||
# hosts_allow_sip: defines nets where we accept SIP traffic from
|
||||
# hosts_deny_sip: defines nets where we deny SIP traffic from
|
||||
#
|
||||
# - The deny list takes precedence over the allow lists.
|
||||
# - The allow_reg list imples also allowance for sip.
|
||||
#
|
||||
# Example for usage:
|
||||
# local private net -> allow_reg list
|
||||
# external nets (where we accept incomming calls from) -> allow_sip
|
||||
#
|
||||
#hosts_allow_reg = 192.168.1.8/24
|
||||
#hosts_allow_sip = 123.45.0.0/16,123.46.0.0/16
|
||||
#hosts_deny_sip = 10.0.0.0/8,11.0.0.0/8
|
||||
|
||||
|
||||
######################################################################
|
||||
# Access control.
|
||||
# 5060 is usually the correct choise - don't change is unless you
|
||||
# know what you're doing
|
||||
#
|
||||
@ -58,7 +82,22 @@ rtp_port_high = 7080
|
||||
rtp_timeout = 60
|
||||
|
||||
######################################################################
|
||||
# DBCLASS_BABBLE 0x00000001 // babble (like entering/leaving fnc)
|
||||
# Proxy authentication
|
||||
# If proxy_auth_realm is defined (a string), clients will be forced
|
||||
# to authenticate themselfes at the proxy (for registration only).
|
||||
# To disable Authentication, simply comment out this line.
|
||||
#
|
||||
#proxy_auth_realm = Authentication_Realm
|
||||
#
|
||||
# the password to use (right now, only one global password for
|
||||
# registration is supported -> same for all local clients)
|
||||
#
|
||||
#proxy_auth_passwd = password
|
||||
|
||||
######################################################################
|
||||
# Debug level... (setting to -1 will enable everything)
|
||||
#
|
||||
# DBCLASS_BABBLE 0x00000001 // babble (like entering/leaving func)
|
||||
# DBCLASS_NET 0x00000002 // network
|
||||
# DBCLASS_SIP 0x00000004 // SIP manipulations
|
||||
# DBCLASS_REG 0x00000008 // Client registration
|
||||
@ -68,6 +107,8 @@ rtp_timeout = 60
|
||||
# DBCLASS_NETTRAF 0x00000080 // network traffic
|
||||
# DBCLASS_CONFIG 0x00000100 // configuration
|
||||
# DBCLASS_RTP 0x00000200 // RTP proxy
|
||||
# DBCLASS_ACCESS 0x00000400 // Access list evaluation
|
||||
# DBCLASS_AUTH 0x00000800 // Authentication
|
||||
#
|
||||
debug_level = 0x00000318
|
||||
debug_level = 0x00000000
|
||||
|
||||
|
||||
58
siproxd.spec
Normal file
58
siproxd.spec
Normal file
@ -0,0 +1,58 @@
|
||||
%define name siproxd
|
||||
%define ver 0.2.1
|
||||
%define release 1
|
||||
%define serial 1
|
||||
%define prefix %{_prefix}
|
||||
%define sysconfdir %{_sysconfdir}
|
||||
|
||||
Name: %{name}
|
||||
Summary: A SIP masquerading proxy with RTP support
|
||||
Version: %{ver}
|
||||
Release: %{release}
|
||||
Copyright: GPL
|
||||
Group: Applications/Communications
|
||||
Source0: %{name}-%{ver}.tar.gz
|
||||
|
||||
URL: http://siproxd.sourceforge.net/
|
||||
BuildRoot: %{_tmppath}/%{name}-%{ver}-root
|
||||
Docdir: %{_docdir}
|
||||
|
||||
Requires: libosip >= 0.8.0
|
||||
BuildRequires: libosip >= 0.8.0
|
||||
|
||||
Vendor: Thomas Ries
|
||||
|
||||
Packager: Thomas Ries <tries@gmx.net>
|
||||
|
||||
%description
|
||||
Siprox is an proxy/masquerading daemon for the SIP protocol.
|
||||
It handles registrations of SIP clients on a private IP network
|
||||
and performs rewriting of the SIP message bodies to make SIP
|
||||
connections possible via an masquerading firewall.
|
||||
It allows SIP clients (like kphone, linphone) to work behind
|
||||
an IP masquerading firewall or router.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix} --sysconfdir=%{sysconfdir}
|
||||
make
|
||||
|
||||
%install
|
||||
make prefix=$RPM_BUILD_ROOT%{prefix} PIXDESTDIR=$RPM_BUILD_ROOT sysconfdir=$RPM_BUILD_ROOT%{sysconfdir} install
|
||||
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-, root, root)
|
||||
%doc COPYING README AUTHORS INSTALL NEWS ChangeLog
|
||||
%{_bindir}/siproxd
|
||||
|
||||
%changelog
|
||||
* Sat Sep 21 2002 Thomas Ries <tries@gmx.net>
|
||||
- first RPM support
|
||||
@ -23,9 +23,10 @@ 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 rtpproxy.c
|
||||
log.c readconf.c rtpproxy.c accessctl.c \
|
||||
security.c auth.c
|
||||
|
||||
noinst_HEADERS = log.h siproxd.h
|
||||
noinst_HEADERS = log.h siproxd.h digcalc.h
|
||||
|
||||
EXTRA_DIST = .buildno
|
||||
|
||||
|
||||
166
src/accessctl.c
Normal file
166
src/accessctl.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osip/smsg.h>
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "log.h"
|
||||
|
||||
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
BUILDSTR " $";
|
||||
|
||||
|
||||
/* configuration storage */
|
||||
struct siproxd_config configuration;
|
||||
|
||||
/* prototypes used locally only */
|
||||
int process_aclist (char *aclist, struct sockaddr_in from);
|
||||
|
||||
|
||||
/*
|
||||
* verifies the from address agains the access lists
|
||||
* defined in the configuration file.
|
||||
*
|
||||
* returns a bitmask with ACCESSCTL_SIP, ACCESSCTL_REG
|
||||
*/
|
||||
int check_accesslist (struct sockaddr_in from) {
|
||||
int access = 0;
|
||||
|
||||
DEBUGC(DBCLASS_ACCESS,"deny list (SIP):%s",configuration.hosts_deny_sip);
|
||||
DEBUGC(DBCLASS_ACCESS,"allow list (SIP):%s",configuration.hosts_allow_sip);
|
||||
DEBUGC(DBCLASS_ACCESS,"allow list (REG):%s",configuration.hosts_allow_reg);
|
||||
|
||||
/*
|
||||
* check DENY list
|
||||
*/
|
||||
if ( (configuration.hosts_deny_sip !=NULL) &&
|
||||
(strcmp(configuration.hosts_deny_sip,"")!=0) ) {
|
||||
/* non-empty list -> check agains it */
|
||||
if (process_aclist(configuration.hosts_deny_sip, from)) {
|
||||
/* yup - this one is blacklisted */
|
||||
DEBUGC(DBCLASS_ACCESS,"caught by deny list");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check SIP allow list
|
||||
*/
|
||||
if ( (configuration.hosts_allow_sip !=NULL) &&
|
||||
(strcmp(configuration.hosts_allow_sip,"")!=0) ) {
|
||||
/* non-empty list -> check agains it */
|
||||
if (process_aclist(configuration.hosts_allow_sip, from)) {
|
||||
/* SIP access granted */
|
||||
DEBUGC(DBCLASS_ACCESS,"granted SIP access");
|
||||
access |= ACCESSCTL_SIP;
|
||||
}
|
||||
} else {
|
||||
access |= ACCESSCTL_SIP;
|
||||
}
|
||||
|
||||
/*
|
||||
* check SIP registration allow list
|
||||
*/
|
||||
if ( (configuration.hosts_allow_reg !=NULL) &&
|
||||
(strcmp(configuration.hosts_allow_reg,"")!=0) ) {
|
||||
/* non-empty list -> check agains it */
|
||||
if (process_aclist(configuration.hosts_allow_reg, from)) {
|
||||
/* SIP registration access granted */
|
||||
DEBUGC(DBCLASS_ACCESS,"granted REG/SIP access");
|
||||
access |= ACCESSCTL_REG | ACCESSCTL_SIP;
|
||||
}
|
||||
} else {
|
||||
access |= ACCESSCTL_REG;
|
||||
}
|
||||
|
||||
return (access);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* checks for a match of the 'from' address with the supplies
|
||||
* access list.
|
||||
*
|
||||
* return 1 for MATCH, 0 otherwise
|
||||
*/
|
||||
int process_aclist (char *aclist, struct sockaddr_in from) {
|
||||
int i;
|
||||
int lastentry;
|
||||
char *p1, *p2;
|
||||
char address[32]; /* dotted decimal IP - max 15 chars*/
|
||||
char mask[8]; /* mask - max 2 digits */
|
||||
struct in_addr inaddr;
|
||||
unsigned int bitmask;
|
||||
|
||||
|
||||
for (i=0, p1=aclist, lastentry=0;
|
||||
!lastentry; i++) {
|
||||
|
||||
/*
|
||||
* extract one entry from the access list
|
||||
*/
|
||||
/* address */
|
||||
p2=strchr(p1,'/');
|
||||
if (!p2) {
|
||||
ERROR("CONFIG: hosts_deny_sip - no mask separator found");
|
||||
return 0;
|
||||
}
|
||||
memset(address,0,sizeof(address));
|
||||
memcpy(address,p1,p2-p1);
|
||||
|
||||
|
||||
/* mask */
|
||||
p1=strchr(p2,',');
|
||||
p1=p2+1;
|
||||
p2=strchr(p1,',');
|
||||
if (!p2) { /* then this must be the last entry in the list */
|
||||
p2=strchr(p1,'\0');
|
||||
lastentry=1;
|
||||
}
|
||||
memset(mask,0,sizeof(mask));
|
||||
memcpy(mask,p1,p2-p1);
|
||||
p1=p2+1;
|
||||
|
||||
DEBUGC(DBCLASS_ACCESS,"[%i] extracted address=%s", i, address);
|
||||
DEBUGC(DBCLASS_ACCESS,"[%i] extracted mask =%s", i, mask);
|
||||
|
||||
/*
|
||||
* check for a match
|
||||
*/
|
||||
get_ip_by_host(address, &inaddr);
|
||||
bitmask=~(0xffffffff>>atoi(mask));
|
||||
|
||||
DEBUGC(DBCLASS_ACCESS,"[%i] (%p) <-> (%p)", i,
|
||||
ntohl(inaddr.s_addr) & bitmask,
|
||||
ntohl(from.sin_addr.s_addr) & bitmask);
|
||||
|
||||
if ( (ntohl(inaddr.s_addr) & bitmask) ==
|
||||
(ntohl(from.sin_addr.s_addr) & bitmask) ) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
351
src/auth.c
Normal file
351
src/auth.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osip/smsg.h>
|
||||
#include <osip/port.h>
|
||||
#include <osip/global.h>
|
||||
#include <osip/md5.h>
|
||||
#include "digcalc.h"
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "log.h"
|
||||
|
||||
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
BUILDSTR " $";
|
||||
|
||||
/* configuration storage */
|
||||
extern struct siproxd_config configuration;
|
||||
|
||||
/* local protorypes */
|
||||
static char *auth_generate_nonce(void);
|
||||
static int auth_check(proxy_authorization_t *proxy_auth);
|
||||
|
||||
/*
|
||||
* perform proxy authentication
|
||||
*
|
||||
* sts = 0 : authentication ok / not needed
|
||||
* sts = 1 : authentication failed
|
||||
* sts = 2 : authentication needed
|
||||
*/
|
||||
int authenticate_proxy(sip_t *request) {
|
||||
proxy_authorization_t *proxy_auth;
|
||||
|
||||
/* required by config ? (if not, return 0)*/
|
||||
if (configuration.proxy_auth_realm==NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* supplied by UA? (if not, return 1)*/
|
||||
msg_getproxy_authorization(request, 0, &proxy_auth);
|
||||
if (proxy_auth == NULL) {
|
||||
DEBUGC(DBCLASS_AUTH,"proxy-auth required, not supplied by UA");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
/* verify supplied authentication */
|
||||
if (auth_check(proxy_auth) == 0) {
|
||||
DEBUGC(DBCLASS_AUTH,"proxy-auth succeeded");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* authentication failed */
|
||||
DEBUGC(DBCLASS_AUTH,"proxy-auth failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int auth_include_authrq(sip_t *response) {
|
||||
int sts;
|
||||
char str[256];
|
||||
|
||||
/*
|
||||
Example of an Proxy-Authenticate header:
|
||||
Proxy-Authenticate: Digest realm="atlanta.com",
|
||||
domain="sip:ss1.carrier.com", qop="auth",
|
||||
nonce="f84f1cec41e6cbe5aea9c8e88d359",
|
||||
opaque="", stale=FALSE, algorithm=MD5
|
||||
*/
|
||||
|
||||
/* 40static + 32nonce + \0 -> max 183 */
|
||||
sprintf(str, "Digest realm=\"%.180s\", "
|
||||
"nonce=\"%s\", "
|
||||
"algorithm=MD5",
|
||||
configuration.proxy_auth_realm,
|
||||
auth_generate_nonce());
|
||||
|
||||
sts = msg_setproxy_authenticate(response, str);
|
||||
|
||||
DEBUGC(DBCLASS_AUTH," msg_setproxy_authenticate sts=%i",sts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static char *auth_generate_nonce() {
|
||||
static char nonce[40];
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
|
||||
/* yeah, I know... should be a better algorithm */
|
||||
sprintf(nonce, "%8.8lx%8.8lx%8.8x%8.8x",
|
||||
tv.tv_sec, tv.tv_usec, rand(), rand() );
|
||||
|
||||
DEBUGC(DBCLASS_AUTH," created nonce=\"%s\"",nonce);
|
||||
return nonce;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* verify the supplied authentication information from UA
|
||||
*
|
||||
* returns 0 if succeeded
|
||||
* returns 1 if failed
|
||||
*/
|
||||
static int auth_check(proxy_authorization_t *proxy_auth) {
|
||||
char *password=NULL;
|
||||
int sts;
|
||||
|
||||
HASHHEX HA1;
|
||||
HASHHEX HA2 = "";
|
||||
HASHHEX Lcl_Response;
|
||||
|
||||
char *Username = NULL;
|
||||
char *Realm = NULL;
|
||||
char *Nonce = NULL;
|
||||
char *CNonce = NULL;
|
||||
char *NonceCount = NULL;
|
||||
char *Qpop = NULL;
|
||||
char *Uri = NULL;
|
||||
char *Response = NULL;
|
||||
|
||||
/* if item exists, allocate& copy string without quotes */
|
||||
if (proxy_auth->username)
|
||||
Username=sgetcopy_unquoted_string(proxy_auth->username);
|
||||
|
||||
if (proxy_auth->realm)
|
||||
Realm=sgetcopy_unquoted_string(proxy_auth->realm);
|
||||
|
||||
if (proxy_auth->nonce)
|
||||
Nonce=sgetcopy_unquoted_string(proxy_auth->nonce);
|
||||
|
||||
if (proxy_auth->cnonce)
|
||||
CNonce=sgetcopy_unquoted_string(proxy_auth->cnonce);
|
||||
|
||||
if (proxy_auth->nonce_count)
|
||||
NonceCount=sgetcopy_unquoted_string(proxy_auth->nonce_count);
|
||||
|
||||
if (proxy_auth->message_qop)
|
||||
Qpop=sgetcopy_unquoted_string(proxy_auth->message_qop);
|
||||
|
||||
if (proxy_auth->uri)
|
||||
Uri=sgetcopy_unquoted_string(proxy_auth->uri);
|
||||
|
||||
if (proxy_auth->response)
|
||||
Response=sgetcopy_unquoted_string(proxy_auth->response);
|
||||
|
||||
/* get password from configuration */
|
||||
if (configuration.proxy_auth_passwd)
|
||||
password=configuration.proxy_auth_passwd;
|
||||
else
|
||||
password="";
|
||||
|
||||
DEBUGC(DBCLASS_BABBLE," username=\"%s\"",Username );
|
||||
DEBUGC(DBCLASS_BABBLE," realm =\"%s\"",Realm );
|
||||
DEBUGC(DBCLASS_BABBLE," nonce =\"%s\"",Nonce );
|
||||
DEBUGC(DBCLASS_BABBLE," cnonce =\"%s\"",CNonce );
|
||||
DEBUGC(DBCLASS_BABBLE," nonce_cn=\"%s\"",NonceCount);
|
||||
DEBUGC(DBCLASS_BABBLE," qpop =\"%s\"",Qpop );
|
||||
DEBUGC(DBCLASS_BABBLE," uri =\"%s\"",Uri );
|
||||
DEBUGC(DBCLASS_BABBLE," response=\"%s\"",Response );
|
||||
|
||||
/* calculate the MD5 digest (heavily inspired from linphone code) */
|
||||
DigestCalcHA1("MD5", Username, Realm, password, Nonce, CNonce, HA1);
|
||||
DigestCalcResponse(HA1, Nonce, NonceCount, CNonce, Qpop,
|
||||
"REGISTER", Uri, HA2, Lcl_Response);
|
||||
|
||||
DEBUGC(DBCLASS_BABBLE," calculated Response=\"%s\"", Lcl_Response);
|
||||
|
||||
if (strcmp(Lcl_Response, Response)==0) {
|
||||
DEBUGC(DBCLASS_AUTH," Authentication succeeded");
|
||||
sts = 0;
|
||||
} else {
|
||||
DEBUGC(DBCLASS_AUTH," Authentication failed");
|
||||
sts = 1;
|
||||
}
|
||||
|
||||
/* free allocated memory from above */
|
||||
if (Username) free(Username);
|
||||
if (Realm) free(Realm);
|
||||
if (Nonce) free(Nonce);
|
||||
if (CNonce) free(CNonce);
|
||||
if (NonceCount) free(NonceCount);
|
||||
if (Qpop) free(Qpop);
|
||||
if (Uri) free(Uri);
|
||||
if (Response) free(Response);
|
||||
|
||||
return sts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------
|
||||
The routines below have been taken from linphone
|
||||
(osipua/src/authentication.c)
|
||||
-------------------------------------------------------------------------
|
||||
-------------------------------------------------------------------------*/
|
||||
|
||||
void CvtHex(
|
||||
IN HASH Bin,
|
||||
OUT HASHHEX Hex
|
||||
)
|
||||
{
|
||||
unsigned short i;
|
||||
unsigned char j;
|
||||
|
||||
for (i = 0; i < HASHLEN; i++) {
|
||||
j = (Bin[i] >> 4) & 0xf;
|
||||
if (j <= 9)
|
||||
Hex[i*2] = (j + '0');
|
||||
else
|
||||
Hex[i*2] = (j + 'a' - 10);
|
||||
j = Bin[i] & 0xf;
|
||||
if (j <= 9)
|
||||
Hex[i*2+1] = (j + '0');
|
||||
else
|
||||
Hex[i*2+1] = (j + 'a' - 10);
|
||||
};
|
||||
Hex[HASHHEXLEN] = '\0';
|
||||
};
|
||||
|
||||
/* calculate H(A1) as per spec */
|
||||
void DigestCalcHA1(
|
||||
IN char * pszAlg,
|
||||
IN char * pszUserName,
|
||||
IN char * pszRealm,
|
||||
IN char * pszPassword,
|
||||
IN char * pszNonce,
|
||||
IN char * pszCNonce,
|
||||
OUT HASHHEX SessionKey
|
||||
)
|
||||
{
|
||||
MD5_CTX Md5Ctx;
|
||||
HASH HA1;
|
||||
|
||||
MD5Init(&Md5Ctx);
|
||||
MD5Update(&Md5Ctx, pszUserName, strlen(pszUserName));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszRealm, strlen(pszRealm));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszPassword, strlen(pszPassword));
|
||||
MD5Final(HA1, &Md5Ctx);
|
||||
|
||||
if ((pszAlg!=NULL)&&strcasecmp(pszAlg, "md5-sess") == 0) {
|
||||
MD5Init(&Md5Ctx);
|
||||
MD5Update(&Md5Ctx, HA1, HASHLEN);
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
|
||||
MD5Final(HA1, &Md5Ctx);
|
||||
};
|
||||
CvtHex(HA1, SessionKey);
|
||||
};
|
||||
|
||||
/* calculate request-digest/response-digest as per HTTP Digest spec */
|
||||
void DigestCalcResponse(
|
||||
IN HASHHEX HA1, /* H(A1) */
|
||||
IN char * pszNonce, /* nonce from server */
|
||||
IN char * pszNonceCount, /* 8 hex digits */
|
||||
IN char * pszCNonce, /* client nonce */
|
||||
IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
|
||||
IN char * pszMethod, /* method from the request */
|
||||
IN char * pszDigestUri, /* requested URL */
|
||||
IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
|
||||
OUT HASHHEX Response /* request-digest or response-digest */
|
||||
)
|
||||
{
|
||||
MD5_CTX Md5Ctx;
|
||||
HASH HA2;
|
||||
HASH RespHash;
|
||||
HASHHEX HA2Hex;
|
||||
|
||||
// calculate H(A2)
|
||||
MD5Init(&Md5Ctx);
|
||||
MD5Update(&Md5Ctx, pszMethod, strlen(pszMethod));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszDigestUri, strlen(pszDigestUri));
|
||||
|
||||
if (pszQop!=NULL) {
|
||||
goto auth_withqop;
|
||||
};
|
||||
|
||||
// auth_withoutqop:
|
||||
MD5Final(HA2, &Md5Ctx);
|
||||
CvtHex(HA2, HA2Hex);
|
||||
|
||||
// calculate response
|
||||
MD5Init(&Md5Ctx);
|
||||
MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
|
||||
goto end;
|
||||
|
||||
auth_withqop:
|
||||
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
|
||||
MD5Final(HA2, &Md5Ctx);
|
||||
CvtHex(HA2, HA2Hex);
|
||||
|
||||
// calculate response
|
||||
MD5Init(&Md5Ctx);
|
||||
MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszNonce, strlen(pszNonce));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszNonceCount, strlen(pszNonceCount));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszCNonce, strlen(pszCNonce));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
MD5Update(&Md5Ctx, pszQop, strlen(pszQop));
|
||||
MD5Update(&Md5Ctx, ":", 1);
|
||||
|
||||
end:
|
||||
MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
|
||||
MD5Final(RespHash, &Md5Ctx);
|
||||
CvtHex(RespHash, Response);
|
||||
};
|
||||
|
||||
|
||||
40
src/digcalc.h
Normal file
40
src/digcalc.h
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
/* TAKEN from rcf2617.txt */
|
||||
|
||||
#ifndef _DIGCALC_H_
|
||||
#define _DIGCALC_H_
|
||||
|
||||
#define HASHLEN 16
|
||||
typedef char HASH[HASHLEN];
|
||||
#define HASHHEXLEN 32
|
||||
typedef char HASHHEX[HASHHEXLEN+1];
|
||||
#define IN
|
||||
#define OUT
|
||||
|
||||
/* calculate H(A1) as per HTTP Digest spec */
|
||||
void DigestCalcHA1(
|
||||
IN char * pszAlg,
|
||||
IN char * pszUserName,
|
||||
IN char * pszRealm,
|
||||
IN char * pszPassword,
|
||||
IN char * pszNonce,
|
||||
IN char * pszCNonce,
|
||||
OUT HASHHEX SessionKey
|
||||
);
|
||||
|
||||
/* calculate request-digest/response-digest as per HTTP Digest spec */
|
||||
void DigestCalcResponse(
|
||||
IN HASHHEX HA1, /* H(A1) */
|
||||
IN char * pszNonce, /* nonce from server */
|
||||
IN char * pszNonceCount, /* 8 hex digits */
|
||||
IN char * pszCNonce, /* client nonce */
|
||||
IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
|
||||
IN char * pszMethod, /* method from the request */
|
||||
IN char * pszDigestUri, /* requested URL */
|
||||
IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
|
||||
OUT HASHHEX Response /* request-digest or response-digest */
|
||||
);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
34
src/log.c
34
src/log.c
@ -25,11 +25,14 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <syslog.h>
|
||||
|
||||
|
||||
static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\
|
||||
BUILDSTR " $";
|
||||
|
||||
|
||||
int log_to_syslog=0;
|
||||
int debug_pattern=0;
|
||||
|
||||
|
||||
@ -37,6 +40,9 @@ void log_set_pattern(int pattern) {
|
||||
debug_pattern=pattern;
|
||||
}
|
||||
|
||||
void log_set_tosyslog(int tosyslog) {
|
||||
log_to_syslog=tosyslog;
|
||||
}
|
||||
|
||||
/* for all the LOGGING routines:
|
||||
They should figure out if we are running as a daemon, then write
|
||||
@ -48,17 +54,26 @@ void log_debug(int class, char *file, int line, const char *format, ...) {
|
||||
va_list ap;
|
||||
time_t t;
|
||||
struct tm *tim;
|
||||
char string[128];
|
||||
|
||||
|
||||
if ((debug_pattern & class) == 0) return;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
if (! log_to_syslog) {
|
||||
/* not running as daemon - log to STDERR */
|
||||
time(&t);
|
||||
tim=localtime(&t);
|
||||
fprintf(stderr,"%2.2i:%2.2i:%2.2i %s:%i ", tim->tm_hour,
|
||||
tim->tm_min, tim->tm_sec, file, line);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr,"\n");
|
||||
} else {
|
||||
/* running as daemon - log via SYSLOG facility */
|
||||
vsnprintf(string, sizeof(string), format, ap);
|
||||
syslog(LOG_USER|LOG_DEBUG, "%s:%i %s", file, line, string);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
@ -71,15 +86,23 @@ void log_error(char *file, int line, const char *format, ...) {
|
||||
va_list ap;
|
||||
time_t t;
|
||||
struct tm *tim;
|
||||
char string[128];
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
if (! log_to_syslog) {
|
||||
/* not running as daemon - log to STDERR */
|
||||
time(&t);
|
||||
tim=localtime(&t);
|
||||
fprintf(stderr,"%2.2i:%2.2i:%2.2i ERROR:%s:%i ",tim->tm_hour,
|
||||
tim->tm_min, tim->tm_sec,file,line);
|
||||
tim->tm_min, tim->tm_sec, file, line);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr,"\n");
|
||||
} else {
|
||||
/* running as daemon - log via SYSLOG facility */
|
||||
vsnprintf(string, sizeof(string), format, ap);
|
||||
syslog(LOG_USER|LOG_WARNING, "%s:%i %s", file, line, string);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
@ -92,15 +115,23 @@ void log_warn(char *file, int line, const char *format, ...) {
|
||||
va_list ap;
|
||||
time_t t;
|
||||
struct tm *tim;
|
||||
char string[128];
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
if (! log_to_syslog) {
|
||||
/* not running as daemon - log to STDERR */
|
||||
time(&t);
|
||||
tim=localtime(&t);
|
||||
fprintf(stderr,"%2.2i:%2.2i:%2.2i WARNING:%s:%i ",tim->tm_hour,
|
||||
tim->tm_min, tim->tm_sec,file,line);
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr,"\n");
|
||||
} else {
|
||||
/* running as daemon - log via SYSLOG facility */
|
||||
vsnprintf(string, sizeof(string), format, ap);
|
||||
syslog(LOG_USER|LOG_NOTICE, "%s:%i %s", file, line, string);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
fflush(stderr);
|
||||
@ -114,6 +145,7 @@ void log_dump_buffer(int class, char *file, int line,
|
||||
int i;
|
||||
|
||||
if ((debug_pattern & class) == 0) return;
|
||||
if (log_to_syslog) return;
|
||||
|
||||
fprintf(stderr,"---BUFFER DUMP follows---\n");
|
||||
for (i=0;i<length;i++) {
|
||||
|
||||
@ -30,10 +30,14 @@
|
||||
#define DBCLASS_NETTRAF 0x00000080 // network traffic
|
||||
#define DBCLASS_CONFIG 0x00000100 // configuration
|
||||
#define DBCLASS_RTP 0x00000200 // RTP proxy
|
||||
#define DBCLASS_ACCESS 0x00000400 // Access list evaluation
|
||||
#define DBCLASS_AUTH 0x00000800 // Authentication
|
||||
|
||||
|
||||
void log_set_pattern(int pattern);
|
||||
void log_set_tosyslog(int tosyslog);
|
||||
|
||||
#define DEBUG(F...) log_debug(1,__FILE__, __LINE__,F)
|
||||
void log_set_pattern(int pattern);
|
||||
|
||||
#define DEBUGC(C,F...) log_debug(C,__FILE__, __LINE__,F)
|
||||
void log_debug(int class, char *file, int line, const char *format, ...);
|
||||
|
||||
@ -188,6 +188,9 @@ int proxy_request (sip_t *request) {
|
||||
|
||||
default:
|
||||
DEBUGC(DBCLASS_PROXY,"request: refuse to proxy - UA not registered?");
|
||||
WARN("request from/to unregistered UA (%s@%s)",
|
||||
request->from->url->username,
|
||||
request->from->url->host);
|
||||
/* some clients seem to run amok when passing back a negative response */
|
||||
// proxy_gen_response(request, 403 /*forbidden*/);
|
||||
return 1;
|
||||
@ -201,7 +204,7 @@ int proxy_request (sip_t *request) {
|
||||
/* 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 OUTBOUNT proxy is activated!
|
||||
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
|
||||
*/
|
||||
@ -504,6 +507,8 @@ int proxy_del_myvia (sip_t *response) {
|
||||
/*
|
||||
* PROXY_REWRITE_INVITATION_BODY
|
||||
*
|
||||
* rewrites the outgoing INVITATION packet
|
||||
*
|
||||
*/
|
||||
int proxy_rewrite_invitation_body(sip_t *mymsg){
|
||||
body_t *body;
|
||||
|
||||
@ -122,6 +122,12 @@ static int parse_config (FILE *configfile) {
|
||||
{ "rtp_proxy_enable", TYP_INT4, &configuration.rtp_proxy_enable },
|
||||
{ "user", TYP_STRING, &configuration.user },
|
||||
{ "chrootjail", TYP_STRING, &configuration.chrootjail },
|
||||
{ "hosts_allow_reg", TYP_STRING, &configuration.hosts_allow_reg },
|
||||
{ "hosts_allow_sip", TYP_STRING, &configuration.hosts_allow_sip },
|
||||
{ "hosts_deny_sip", TYP_STRING, &configuration.hosts_deny_sip },
|
||||
{ "hosts_deny_sip", TYP_STRING, &configuration.hosts_deny_sip },
|
||||
{ "proxy_auth_realm", TYP_STRING, &configuration.proxy_auth_realm },
|
||||
{ "proxy_auth_passwd", TYP_STRING, &configuration.proxy_auth_passwd },
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
@ -168,6 +174,7 @@ static int parse_config (FILE *configfile) {
|
||||
break;
|
||||
|
||||
case TYP_STRING:
|
||||
// num=sscanf(ptr,"%a[^#]",(char**)configoptions[j].dest);
|
||||
num=sscanf(ptr,"%as",(char**)configoptions[j].dest);
|
||||
DEBUGC(DBCLASS_BABBLE,"STRING=%s",*(char**)configoptions[j].dest);
|
||||
break;
|
||||
|
||||
@ -54,15 +54,32 @@ void register_init(void) {
|
||||
* handles register requests and updates the URL mapping table
|
||||
* sts = 0 : successfully registered
|
||||
* sts = 1 : registration failed
|
||||
* sts = 2 : authentication needed
|
||||
*/
|
||||
int register_client(sip_t *my_msg) {
|
||||
int i,j;
|
||||
int i, j, sts;
|
||||
int expires;
|
||||
time_t time_now;
|
||||
url_t *url1_to, *url1_contact;
|
||||
url_t *url2_to, *url2_contact;
|
||||
header_t *expires_hdr;
|
||||
|
||||
/*
|
||||
do proxy authentication
|
||||
*/
|
||||
sts = authenticate_proxy(my_msg);
|
||||
if (sts == 1) {
|
||||
/* failed */
|
||||
WARN("proxy authentication failed for %s@%s",
|
||||
my_msg->to->url->username,my_msg->to->url->host);
|
||||
return (1);
|
||||
} else if (sts == 2) {
|
||||
/* needed */
|
||||
DEBUGC(DBCLASS_REG,"proxy authentication needed for %s@%s",
|
||||
my_msg->to->url->username,my_msg->to->url->host);
|
||||
return (2);
|
||||
}
|
||||
|
||||
/*
|
||||
fetch 1st Via entry and remember this address. Incomming requests
|
||||
for the registered address have to be passed on to that host.
|
||||
@ -181,8 +198,9 @@ void register_agemap(void) {
|
||||
|
||||
/*
|
||||
* send answer to a registration request.
|
||||
* flag = 0 -> positive answer
|
||||
* flag != 0 -> negative answer
|
||||
* flag = 0 -> positive answer (200)
|
||||
* flag = 1 -> negative answer (503)
|
||||
* flag = 2 -> proxy authentication needed (407)
|
||||
*/
|
||||
int register_response(sip_t *request, int flag) {
|
||||
sip_t *response;
|
||||
@ -195,8 +213,20 @@ int register_response(sip_t *request, int flag) {
|
||||
header_t *expires_hdr;
|
||||
|
||||
/* ok -> 200, fail -> 503 */
|
||||
if (flag == 0) code = 200;
|
||||
else code = 503;
|
||||
switch (flag) {
|
||||
case 0:
|
||||
code = 200; /* OK */
|
||||
break;
|
||||
case 1:
|
||||
code = 503; /* failed */
|
||||
break;
|
||||
case 2:
|
||||
code = 407; /* proxy authentication needed */
|
||||
break;
|
||||
default:
|
||||
code = 503; /* failed */
|
||||
break;
|
||||
}
|
||||
|
||||
/* create the response template */
|
||||
if ((response=msg_make_template_reply(request, code))==NULL) {
|
||||
@ -210,6 +240,11 @@ int register_response(sip_t *request, int flag) {
|
||||
msg_setexpires(response, expires_hdr->hvalue);
|
||||
}
|
||||
|
||||
/* if we send back an proxy authentication needed,
|
||||
include the Proxy-Authenticate field */
|
||||
if (code == 407) {
|
||||
auth_include_authrq(response);
|
||||
}
|
||||
|
||||
/* get the IP address from existing VIA header */
|
||||
msg_getvia (response, 0, &via);
|
||||
|
||||
46
src/security.c
Normal file
46
src/security.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
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 <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <osip/smsg.h>
|
||||
|
||||
#include "siproxd.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
/*
|
||||
* do security and integrity checks on the received packet
|
||||
*
|
||||
* returns >0 if ok
|
||||
* 0 if the packed did not pass the checks
|
||||
*/
|
||||
int securitycheck(char *sip_buffer, int size){
|
||||
|
||||
/* TODO: still way to go here ... */
|
||||
return 1;
|
||||
}
|
||||
@ -26,6 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
@ -60,6 +61,8 @@ int main (int argc, char *argv[])
|
||||
{
|
||||
int sts;
|
||||
int i;
|
||||
int access;
|
||||
struct sockaddr_in from;
|
||||
char buff [BUFFER_SIZE];
|
||||
sip_t *my_msg=NULL;
|
||||
|
||||
@ -69,13 +72,11 @@ int main (int argc, char *argv[])
|
||||
char configfile[64]="siproxd"; /* basename of configfile */
|
||||
int config_search=1; /* search the config file */
|
||||
|
||||
/* prepare default configuration */
|
||||
configuration.debuglevel=0;
|
||||
configuration.daemonize=0;
|
||||
/*
|
||||
* prepare default configuration
|
||||
*/
|
||||
memset (&configuration, 0, sizeof(configuration));
|
||||
configuration.sip_listen_port=SIP_PORT;
|
||||
configuration.inboundhost=NULL;
|
||||
configuration.outboundhost=NULL;
|
||||
configuration.user=NULL;
|
||||
|
||||
log_set_pattern(configuration.debuglevel);
|
||||
|
||||
@ -161,6 +162,7 @@ int main (int argc, char *argv[])
|
||||
/* close STDIN, STDOUT, STDERR */
|
||||
close(0);close(1);close(2);
|
||||
#endif
|
||||
log_set_tosyslog(1);
|
||||
}
|
||||
|
||||
|
||||
@ -178,17 +180,28 @@ int main (int argc, char *argv[])
|
||||
/* got input, process */
|
||||
DEBUGC(DBCLASS_BABBLE,"back from sip_wait");
|
||||
|
||||
i=sipsock_read(&buff, sizeof(buff));
|
||||
/*
|
||||
* more integrity checks of received packet needed !!
|
||||
* it's possible to crash msg_parse with some crap-input.
|
||||
*/
|
||||
i=sipsock_read(&buff, sizeof(buff), &from);
|
||||
|
||||
/* evaluate the access lists */
|
||||
access=check_accesslist(from);
|
||||
if (access == 0) continue; /* there are no resources to free */
|
||||
|
||||
/* integrity checks */
|
||||
sts=securitycheck(buff, i);
|
||||
if (sts == 0) continue; /* there are no resources to free */
|
||||
|
||||
/* parse the received message */
|
||||
sts=msg_init(&my_msg);
|
||||
sts=msg_parse( my_msg, buff);
|
||||
/*
|
||||
* if message parsing was ok go on - otherwise skip
|
||||
*/
|
||||
if (sts != 0) continue;
|
||||
if (sts != 0) {
|
||||
ERROR("msg_init() failed... this is not good");
|
||||
continue; /* skip, there are no resources to free */
|
||||
}
|
||||
|
||||
sts=msg_parse(my_msg, buff);
|
||||
if (sts != 0) {
|
||||
ERROR("msg_parse() failed... this is not good");
|
||||
goto end_loop; /* skip and free resources */
|
||||
}
|
||||
|
||||
DEBUGC(DBCLASS_SIP,"received SIP type %s:%s",
|
||||
(MSG_IS_REQUEST(my_msg))? "REQ" : "RES",
|
||||
@ -196,19 +209,34 @@ int main (int argc, char *argv[])
|
||||
|
||||
/* if RQ REGISTER, just register and send an answer */
|
||||
if (MSG_IS_REGISTER(my_msg) && MSG_IS_REQUEST(my_msg)) {
|
||||
if (access & ACCESSCTL_REG) {
|
||||
sts = register_client(my_msg);
|
||||
sts = register_response(my_msg, sts);
|
||||
} else {
|
||||
WARN("non-authorized registration attempt from %s",
|
||||
inet_ntoa(from.sin_addr));
|
||||
}
|
||||
|
||||
/* MSG is a request, add current via entry,
|
||||
* do a lookup in the URLMAP table and
|
||||
* send to the final destination */
|
||||
} else if (MSG_IS_REQUEST(my_msg)) {
|
||||
if (access & ACCESSCTL_SIP) {
|
||||
sts = proxy_request(my_msg);
|
||||
} else {
|
||||
WARN("non-authorized request received from %s",
|
||||
inet_ntoa(from.sin_addr));
|
||||
}
|
||||
|
||||
/* MSG is a response, remove current via and
|
||||
* send to next via in chain */
|
||||
} else if (MSG_IS_RESPONSE(my_msg)) {
|
||||
if (access & ACCESSCTL_SIP) {
|
||||
sts = proxy_response(my_msg);
|
||||
} else {
|
||||
WARN("non-authorized response received from %s",
|
||||
inet_ntoa(from.sin_addr));
|
||||
}
|
||||
|
||||
/* unsupported message */
|
||||
} else {
|
||||
@ -221,6 +249,7 @@ int main (int argc, char *argv[])
|
||||
/*
|
||||
* free the SIP message buffers
|
||||
*/
|
||||
end_loop:
|
||||
msg_free(my_msg);
|
||||
free(my_msg);
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
/* sock.c */
|
||||
int sipsock_listen (void);
|
||||
int sipsock_wait(void);
|
||||
int sipsock_read(void *buf, size_t bufsize);
|
||||
int sipsock_read(void *buf, size_t bufsize, struct sockaddr_in *from);
|
||||
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);
|
||||
@ -50,7 +50,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr);
|
||||
int compare_url(url_t *url1, url_t *url2);
|
||||
void secure_enviroment (void);
|
||||
|
||||
/* config.c */
|
||||
/* readconf.c */
|
||||
int read_config(char *name, int search);
|
||||
|
||||
/* rtpproxy.c */
|
||||
@ -60,6 +60,17 @@ int rtp_start_fwd (call_id_t *callid,
|
||||
struct in_addr lcl_client_ipaddr, int lcl_clientport);
|
||||
int rtp_stop_fwd (call_id_t *callid);
|
||||
|
||||
/* accessctl.c */
|
||||
int check_accesslist (struct sockaddr_in from);
|
||||
|
||||
/* security.c */
|
||||
int securitycheck(char *sip_buffer, int size);
|
||||
|
||||
/* auth.c */
|
||||
int authenticate_proxy(sip_t *request);
|
||||
int auth_include_authrq(sip_t *response);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* table to hold the client registrations
|
||||
@ -88,6 +99,11 @@ struct siproxd_config {
|
||||
int rtp_proxy_enable;
|
||||
char *user;
|
||||
char *chrootjail;
|
||||
char *hosts_allow_reg;
|
||||
char *hosts_allow_sip;
|
||||
char *hosts_deny_sip;
|
||||
char *proxy_auth_realm;
|
||||
char *proxy_auth_passwd;
|
||||
};
|
||||
|
||||
|
||||
@ -107,6 +123,11 @@ struct siproxd_config {
|
||||
#define DNS_MAX_AGE 60 // maximum age of an cache entry (sec)
|
||||
#define HOSTNAME_SIZE 32 // max string length of a hostname
|
||||
|
||||
|
||||
#define ACCESSCTL_SIP 1 // for access control - SIP allowed
|
||||
#define ACCESSCTL_REG 2 // --"-- - registrations allowed
|
||||
|
||||
|
||||
/*
|
||||
* optional hacks
|
||||
*/
|
||||
|
||||
@ -78,9 +78,12 @@ int sipsock_wait(void) {
|
||||
return sts;
|
||||
}
|
||||
|
||||
int sipsock_read(void *buf, size_t bufsize) {
|
||||
int sipsock_read(void *buf, size_t bufsize, struct sockaddr_in *from) {
|
||||
int count;
|
||||
count=read(listen_socket, buf, bufsize);
|
||||
socklen_t fromlen;
|
||||
|
||||
fromlen=sizeof(struct sockaddr);
|
||||
count=recvfrom(listen_socket, buf, bufsize, 0, from, &fromlen);
|
||||
|
||||
DEBUGC(DBCLASS_NET,"received UDP packet, count=%i", count);
|
||||
DUMP_BUFFER(DBCLASS_NETTRAF, buf, count);
|
||||
|
||||
@ -179,7 +179,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) {
|
||||
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);
|
||||
DEBUGC(DBCLASS_DNS, "cleaning DNS cache (entry %i)", i);
|
||||
memset (&dns_cache[i], 0, sizeof(dns_cache[0]));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user