diff --git a/ChangeLog b/ChangeLog index bc9410f..dadd7d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/Makefile.am b/Makefile.am index e29e7df..f7d0fd6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,4 +21,4 @@ SUBDIRS = src doc scripts -EXTRA_DIST = TODO RELNOTES +EXTRA_DIST = TODO RELNOTES siproxd.spec diff --git a/README b/README index 8530d3a..d58f58b 100644 --- a/README +++ b/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. + diff --git a/RELNOTES b/RELNOTES index e69440c..4a85798 100644 --- a/RELNOTES +++ b/RELNOTES @@ -1,19 +1,30 @@ 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: diff --git a/TODO b/TODO index a6397b6..80b2ad8 100644 --- a/TODO +++ b/TODO @@ -1,20 +1,22 @@ TODOs, in random order: ======================= -- re-think the registration mechanism (mapping and decision criteria - for in- and outgoing stuff... - -- logging via syslog if running in daemon mode +- client authentication for registration - multiple user feature -- get_ip_by_host: reduce DNS timeouts +- redo return status (make then at least DEFINED constants) -- Documentation +- Documentation (yeah, yeah...) + +- 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 + diff --git a/config.h.in b/config.h.in index 7698c62..776fbd3 100644 --- a/config.h.in +++ b/config.h.in @@ -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 header file. */ #undef HAVE_ERRNO_H diff --git a/configure.in b/configure.in index 62ec6a6..986d4d8 100644 --- a/configure.in +++ b/configure.in @@ -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 \ diff --git a/doc/FAQ b/doc/FAQ new file mode 100644 index 0000000..7244bb3 --- /dev/null +++ b/doc/FAQ @@ -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). +--------------------------------------------------------------------------- diff --git a/doc/Makefile.am b/doc/Makefile.am index 7727465..d7af4fe 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -19,4 +19,4 @@ # -EXTRA_DIST = siproxd.conf.example +EXTRA_DIST = siproxd.conf.example FAQ diff --git a/doc/siproxd.conf.example b/doc/siproxd.conf.example index d197e55..ae784b1 100644 --- a/doc/siproxd.conf.example +++ b/doc/siproxd.conf.example @@ -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 diff --git a/siproxd.spec b/siproxd.spec new file mode 100644 index 0000000..5d39404 --- /dev/null +++ b/siproxd.spec @@ -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 + +%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 +- first RPM support diff --git a/src/Makefile.am b/src/Makefile.am index 3c69bf5..eea67fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 diff --git a/src/accessctl.c b/src/accessctl.c new file mode 100644 index 0000000..430a83e --- /dev/null +++ b/src/accessctl.c @@ -0,0 +1,166 @@ +/* + Copyright (C) 2002 Thomas Ries + + 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 +#include +#include +#include + +#include + +#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; +} diff --git a/src/auth.c b/src/auth.c new file mode 100644 index 0000000..a36c8e1 --- /dev/null +++ b/src/auth.c @@ -0,0 +1,351 @@ +/* + Copyright (C) 2002 Thomas Ries + + 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 +#include +#include + +#include + +#include + +#include +#include +#include +#include +#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); +}; + + diff --git a/src/digcalc.h b/src/digcalc.h new file mode 100644 index 0000000..db1914f --- /dev/null +++ b/src/digcalc.h @@ -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 diff --git a/src/log.c b/src/log.c index 63be1ce..734e7f8 100644 --- a/src/log.c +++ b/src/log.c @@ -25,11 +25,14 @@ #include #include #include +#include + 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,18 +54,27 @@ 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); - 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"); - + 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); return; @@ -71,16 +86,24 @@ 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); - 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); - vfprintf(stderr, format, ap); - fprintf(stderr,"\n"); - + 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); + 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); return; @@ -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); - 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"); + 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;ifrom->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; diff --git a/src/readconf.c b/src/readconf.c index a23fcd8..dca90cd 100644 --- a/src/readconf.c +++ b/src/readconf.c @@ -111,17 +111,23 @@ 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_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 }, - { "user", TYP_STRING, &configuration.user }, - { "chrootjail", TYP_STRING, &configuration.chrootjail }, + { "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 }, + { "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; diff --git a/src/register.c b/src/register.c index 2e1447f..c6ac232 100644 --- a/src/register.c +++ b/src/register.c @@ -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) { @@ -209,7 +239,12 @@ int register_response(sip_t *request, int flag) { if (expires_hdr) { 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); diff --git a/src/security.c b/src/security.c new file mode 100644 index 0000000..60fa185 --- /dev/null +++ b/src/security.c @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002 Thomas Ries + + 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 +#include +#include +#include +#include +#include + +#include + +#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; +} diff --git a/src/siproxd.c b/src/siproxd.c index 06c53e8..bae1606 100644 --- a/src/siproxd.c +++ b/src/siproxd.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -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)) { - sts = register_client(my_msg); - sts = register_response(my_msg, sts); + 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)) { - sts = proxy_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)) { - sts = proxy_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); diff --git a/src/siproxd.h b/src/siproxd.h index e5a40b7..2735298 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -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 */ diff --git a/src/sock.c b/src/sock.c index ffa8c0b..189358b 100644 --- a/src/sock.c +++ b/src/sock.c @@ -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); diff --git a/src/utils.c b/src/utils.c index 255f22e..930d325 100644 --- a/src/utils.c +++ b/src/utils.c @@ -179,7 +179,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { for (i=0; i