diff --git a/ChangeLog b/ChangeLog index b2c0ff3..cc485ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,25 @@ +0.3.2 +===== + 1-Apr-2003: - should now be able to deal with an outbound interface + that is "temporary" DOWN (dial up internet access) + if outbounf IF is down, send back a response to + inbound UAs "408 Request Timeout". + - always log to syslog, also when running in foreground + - changed some WARNINGS into DEBUG statements + - re-arranged some code + - rtpproxy: prepared for proper thread termination on exit + - introduced short term caching for get_ip_by_ifname + - fixed in check for socket() return status +30-May-2003: - always log ERROR, WARNING and INFO to syslog (also + of not running as daemon) + - minor corrections on ERROR printouts + 0.3.1 ===== - 29-May-2003: - released 0.3.1 - fix in configure.in for statically linking to libosip - fix in rewriting SIP messages, figure out proper - destination if *not* rewriting the SIP URI + destination if *not* rewriting the SIP URI - another NULL pointer related crash (no UA header present) 0.3.0 @@ -11,10 +27,10 @@ - 29-May-2003: - released 0.3.0 - supports libosip2 (automatically detect osip1/osip2) - redone authentication - now should work with libosip2 - libosip0.8.8 has a bug (fails in parse_msg) + libosip0.8.8 has a bug (fails in parse_msg) - 28-May-2003: - changes in rewriting SIP messages - not everything is blindly rewritten now (e.g. SUBSCRIBE is NOT) - - fixed resource leak (sockets) in get_ip_by_ifname + - fixed resource leak (sockets) in get_ip_by_ifname - 26-Mar-2003: - Bugfix: some potential NULL pointers passed to atoi() of optional fields in SIP message could lead to crash - 23-Mar-2003: - send 403 FORBIDDEN response to requests addressed diff --git a/TODO b/TODO index 93493d1..357a378 100644 --- a/TODO +++ b/TODO @@ -1,20 +1,19 @@ TODOs, in random order: ======================= -- kphone 3.1: authentication w/ siproxd (libosip 0.8.8, 0.9.0, libosip2) - does not work (parse error in libosip) +- TERM handler -- libosip >0.8.8, libosip2: failure in msg_setproxy_authenticate +- /var/run PID file + +- check via loop and private IP addresses + can comment be used to store a unique ID in there? + +- multiple inbound interfaces - do I need to be aware of inbound at all? - Documentation (yeah, yeah...) - support for proxy chaining - UPNP support? -- feature: don't bind to 0.0.0.0 address, but only to inbound/outbound IF's - (defined by IFNAME) - -- multiple inbound interfaces - - general security issues - security tests for received SIP messages (function securitycheck) @@ -27,3 +26,6 @@ TODOs, in random order: - via loop detection: send 482 error code - support Record-Route header + +- feature: don't bind to 0.0.0.0 address, but only to inbound/outbound IF's + (defined by IFNAME) diff --git a/aclocal.m4 b/aclocal.m4 deleted file mode 100644 index eb682f5..0000000 --- a/aclocal.m4 +++ /dev/null @@ -1,356 +0,0 @@ -dnl aclocal.m4 generated automatically by aclocal 1.4a - -dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. -dnl This file is free software; the Free Software Foundation -dnl gives unlimited permission to copy and/or distribute it, -dnl with or without modifications, as long as this notice is preserved. - -dnl This program is distributed in the hope that it will be useful, -dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without -dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A -dnl PARTICULAR PURPOSE. - -dnl -------------------------------------------------------------------- -dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) -dnl -dnl This macro figures out how to build C programs using POSIX -dnl threads. It sets the PTHREAD_LIBS output variable to the threads -dnl library and linker flags, and the PTHREAD_CFLAGS output variable -dnl to any special C compiler flags that are needed. (The user can also -dnl force certain compiler flags/libs to be tested by setting these -dnl environment variables.) -dnl -dnl Also sets PTHREAD_CC to any special C compiler that is needed for -dnl multi-threaded programs (defaults to the value of CC otherwise). -dnl (This is necessary on AIX to use the special cc_r compiler alias.) -dnl -dnl If you are only building threads programs, you may wish to -dnl use these variables in your default LIBS, CFLAGS, and CC: -dnl -dnl LIBS="$PTHREAD_LIBS $LIBS" -dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" -dnl CC="$PTHREAD_CC" -dnl -dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute -dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE -dnl to that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). -dnl -dnl ACTION-IF-FOUND is a list of shell commands to run if a threads -dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands -dnl to run it if it is not found. If ACTION-IF-FOUND is not specified, -dnl the default action will define HAVE_PTHREAD. -dnl -dnl Please let the authors know if this macro fails on any platform, -dnl or if you have any other suggestions or comments. This macro was -dnl based on work by SGJ on autoconf scripts for FFTW (www.fftw.org) -dnl (with help from M. Frigo), as well as ac_pthread and hb_pthread -dnl macros posted by AFC to the autoconf macro repository. We are also -dnl grateful for the helpful feedback of numerous users. -dnl -dnl @version $Id$ -dnl @author Steven G. Johnson and Alejandro Forero Cuervo - -AC_DEFUN([ACX_PTHREAD], [ -AC_REQUIRE([AC_CANONICAL_HOST]) -acx_pthread_ok=no - -# We used to check for pthread.h first, but this fails if pthread.h -# requires special compiler flags (e.g. on True64 or Sequent). -# It gets checked for in the link test anyway. - -# First of all, check if the user has set any of the PTHREAD_LIBS, -# etcetera environment variables, and if threads linking works using -# them: -if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) - AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) - AC_MSG_RESULT($acx_pthread_ok) - if test x"$acx_pthread_ok" = xno; then - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" - fi - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" -fi - -# We must check for the threads library under a number of different -# names; the ordering is very important because some systems -# (e.g. DEC) have both -lpthread and -lpthreads, where one of the -# libraries is broken (non-POSIX). - -# Create a list of thread flags to try. Items starting with a "-" are -# C compiler flags, and other items are library names, except for "none" -# which indicates that we try without any flags at all. - -acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" - -# The ordering *is* (sometimes) important. Some notes on the -# individual items follow: - -# pthreads: AIX (must check this before -lpthread) -# none: in case threads are in libc; should be tried before -Kthread and -# other compiler flags to prevent continual compiler warnings -# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) -# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) -# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) -# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) -# -pthreads: Solaris/gcc -# -mthreads: Mingw32/gcc, Lynx/gcc -# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it -# doesn't hurt to check since this sometimes defines pthreads too; -# also defines -D_REENTRANT) -# pthread: Linux, etcetera -# --thread-safe: KAI C++ - -case "${host_cpu}-${host_os}" in - *solaris*) - - # On Solaris (at least, for some versions), libc contains stubbed - # (non-functional) versions of the pthreads routines, so link-based - # tests will erroneously succeed. (We need to link with -pthread or - # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather - # a function called by this macro, so we could check for that, but - # who knows whether they'll stub that too in a future libc.) So, - # we'll just look for -pthreads and -lpthread first: - - acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" - ;; -esac - -if test x"$acx_pthread_ok" = xno; then -for flag in $acx_pthread_flags; do - - case $flag in - none) - AC_MSG_CHECKING([whether pthreads work without any flags]) - ;; - - -*) - AC_MSG_CHECKING([whether pthreads work with $flag]) - PTHREAD_CFLAGS="$flag" - ;; - - *) - AC_MSG_CHECKING([for the pthreads library -l$flag]) - PTHREAD_LIBS="-l$flag" - ;; - esac - - save_LIBS="$LIBS" - save_CFLAGS="$CFLAGS" - LIBS="$PTHREAD_LIBS $LIBS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Check for various functions. We must include pthread.h, - # since some functions may be macros. (On the Sequent, we - # need a special flag -Kthread to make this header compile.) - # We check for pthread_join because it is in -lpthread on IRIX - # while pthread_create is in libc. We check for pthread_attr_init - # due to DEC craziness with -lpthreads. We check for - # pthread_cleanup_push because it is one of the few pthread - # functions on Solaris that doesn't have a non-functional libc stub. - # We try pthread_create on general principles. - AC_TRY_LINK([#include ], - [pthread_t th; pthread_join(th, 0); - pthread_attr_init(0); pthread_cleanup_push(0, 0); - pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], - [acx_pthread_ok=yes]) - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - AC_MSG_RESULT($acx_pthread_ok) - if test "x$acx_pthread_ok" = xyes; then - break; - fi - - PTHREAD_LIBS="" - PTHREAD_CFLAGS="" -done -fi - -# Various other checks: -if test "x$acx_pthread_ok" = xyes; then - save_LIBS="$LIBS" - LIBS="$PTHREAD_LIBS $LIBS" - save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS $PTHREAD_CFLAGS" - - # Detect AIX lossage: threads are created detached by default - # and the JOINABLE attribute has a nonstandard name (UNDETACHED). - AC_MSG_CHECKING([for joinable pthread attribute]) - AC_TRY_LINK([#include ], - [int attr=PTHREAD_CREATE_JOINABLE;], - ok=PTHREAD_CREATE_JOINABLE, ok=unknown) - if test x"$ok" = xunknown; then - AC_TRY_LINK([#include ], - [int attr=PTHREAD_CREATE_UNDETACHED;], - ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) - fi - if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then - AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, - [Define to the necessary symbol if this constant - uses a non-standard name on your system.]) - fi - AC_MSG_RESULT(${ok}) - if test x"$ok" = xunknown; then - AC_MSG_WARN([we do not know how to create joinable pthreads]) - fi - - AC_MSG_CHECKING([if more special flags are required for pthreads]) - flag=no - case "${host_cpu}-${host_os}" in - *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; - *solaris* | alpha*-osf*) flag="-D_REENTRANT";; - esac - AC_MSG_RESULT(${flag}) - if test "x$flag" != xno; then - PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" - fi - - LIBS="$save_LIBS" - CFLAGS="$save_CFLAGS" - - # More AIX lossage: must compile with cc_r - AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) -else - PTHREAD_CC="$CC" -fi - -AC_SUBST(PTHREAD_LIBS) -AC_SUBST(PTHREAD_CFLAGS) -AC_SUBST(PTHREAD_CC) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test x"$acx_pthread_ok" = xyes; then - ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) - : -else - acx_pthread_ok=no - $2 -fi - -])dnl ACX_PTHREAD - - -# Like AC_CONFIG_HEADER, but automatically create stamp file. - -AC_DEFUN(AM_CONFIG_HEADER, -[AC_PREREQ([2.12]) -AC_CONFIG_HEADER([$1]) -dnl When config.status generates a header, we must update the stamp-h file. -dnl This file resides in the same directory as the config header -dnl that is generated. We must strip everything past the first ":", -dnl and everything past the last "/". -AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl -ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, -<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, -<>; do - case " <<$>>CONFIG_HEADERS " in - *" <<$>>am_file "*<<)>> - echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx - ;; - esac - am_indx=`expr "<<$>>am_indx" + 1` -done<<>>dnl>>) -changequote([,]))]) - -# Do all the work for Automake. This macro actually does too much -- -# some checks are only needed if your package does certain things. -# But this isn't really a big deal. - -# serial 1 - -dnl Usage: -dnl AM_INIT_AUTOMAKE(package,version, [no-define]) - -AC_DEFUN(AM_INIT_AUTOMAKE, -[AC_REQUIRE([AC_PROG_INSTALL]) -dnl We require 2.13 because we rely on SHELL being computed by configure. -AC_PREREQ([2.13]) -PACKAGE=[$1] -AC_SUBST(PACKAGE) -VERSION=[$2] -AC_SUBST(VERSION) -dnl test to see if srcdir already configured -if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) -fi -ifelse([$3],, -AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) -AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) -AC_REQUIRE([AM_SANITY_CHECK]) -AC_REQUIRE([AC_ARG_PROGRAM]) -dnl FIXME This is truly gross. -missing_dir=`cd $ac_aux_dir && pwd` -AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) -AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) -AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) -AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) -AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) -AC_REQUIRE([AC_PROG_MAKE_SET])]) - -# -# Check to make sure that the build environment is sane. -# - -AC_DEFUN(AM_SANITY_CHECK, -[AC_MSG_CHECKING([whether build environment is sane]) -# Just in case -sleep 1 -echo timestamp > conftestfile -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` - if test "[$]*" = "X"; then - # -L didn't work. - set X `ls -t $srcdir/configure conftestfile` - fi - if test "[$]*" != "X $srcdir/configure conftestfile" \ - && test "[$]*" != "X conftestfile $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken -alias in your environment]) - fi - - test "[$]2" = conftestfile - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -rm -f conftest* -AC_MSG_RESULT(yes)]) - -dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) -dnl The program must properly implement --version. -AC_DEFUN(AM_MISSING_PROG, -[AC_MSG_CHECKING(for working $2) -# Run test in a subshell; some versions of sh will print an error if -# an executable is not found, even if stderr is redirected. -# Redirect stdin to placate older versions of autoconf. Sigh. -if ($2 --version) < /dev/null > /dev/null 2>&1; then - $1=$2 - AC_MSG_RESULT(found) -else - $1="$3/missing $2" - AC_MSG_RESULT(missing) -fi -AC_SUBST($1)]) - diff --git a/configure.in b/configure.in index c35c841..a2bd4a1 100644 --- a/configure.in +++ b/configure.in @@ -24,7 +24,7 @@ dnl Release Version dnl SPD_MAJOR_VERSION=0 SPD_MINOR_VERSION=3 -SPD_MICRO_VERSION=1 +SPD_MICRO_VERSION=2 SPD_VERSION=$SPD_MAJOR_VERSION.$SPD_MINOR_VERSION.$SPD_MICRO_VERSION diff --git a/siproxd.spec b/siproxd.spec index 5fe9ceb..914b6b3 100644 --- a/siproxd.spec +++ b/siproxd.spec @@ -1,5 +1,5 @@ %define name siproxd -%define ver 0.3.1 +%define ver 0.3.2 %define release 1 %define serial 1 %define prefix %{_prefix} diff --git a/src/accessctl.c b/src/accessctl.c index c7b9da9..7c72166 100644 --- a/src/accessctl.c +++ b/src/accessctl.c @@ -118,7 +118,7 @@ int accesslist_check (struct sockaddr_in from) { * STS_FAILURE for no match */ int process_aclist (char *aclist, struct sockaddr_in from) { - int i; + int i, sts; int lastentry; char *p1, *p2; char address[32]; /* dotted decimal IP - max 15 chars*/ @@ -161,7 +161,13 @@ int process_aclist (char *aclist, struct sockaddr_in from) { /* * check for a match */ - get_ip_by_host(address, &inaddr); + sts=get_ip_by_host(address, &inaddr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_ACCESS, "process_aclist: cannot resolve address [%s]", + address); + return STS_FAILURE; + } + bitmask=~(0xffffffff>>atoi(mask)); DEBUGC(DBCLASS_ACCESS,"[%i] (%p) <-> (%p)", i, diff --git a/src/log.c b/src/log.c index 695c055..83c521b 100644 --- a/src/log.c +++ b/src/log.c @@ -104,11 +104,13 @@ void log_error(char *file, int line, const char *format, ...) { tim->tm_min, tim->tm_sec, file, line); vfprintf(stderr, format, ap); fprintf(stderr,"\n"); - } else { +} +// always log INFO, WARN, ERROR to syslog +// } else { /* running as daemon - log via SYSLOG facility */ vsnprintf(string, sizeof(string), format, ap); syslog(LOG_USER|LOG_WARNING, "%s:%i ERROR:%s", file, line, string); - } +// } va_end(ap); fflush(stderr); @@ -133,11 +135,13 @@ void log_warn(char *file, int line, const char *format, ...) { tim->tm_min, tim->tm_sec,file,line); vfprintf(stderr, format, ap); fprintf(stderr,"\n"); - } else { +} +// always log INFO, WARN, ERROR to syslog +// } else { /* running as daemon - log via SYSLOG facility */ vsnprintf(string, sizeof(string), format, ap); syslog(LOG_USER|LOG_NOTICE, "%s:%i WARNING:%s", file, line, string); - } +// } va_end(ap); fflush(stderr); @@ -162,11 +166,13 @@ void log_info(char *file, int line, const char *format, ...) { tim->tm_min, tim->tm_sec,file,line); vfprintf(stderr, format, ap); fprintf(stderr,"\n"); - } else { +} +// always log INFO, WARN, ERROR to syslog +// } else { /* running as daemon - log via SYSLOG facility */ vsnprintf(string, sizeof(string), format, ap); syslog(LOG_USER|LOG_NOTICE, "%s:%i INFO:%s", file, line, string); - } +// } va_end(ap); fflush(stderr); diff --git a/src/proxy.c b/src/proxy.c index 71094a9..6b9d7c5 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -144,6 +144,11 @@ int proxy_request (sip_t *request) { */ case REQTYP_INCOMING: sts = get_ip_by_host(urlmap[i].true_url->host, &sendto_addr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]", + url->host); + return STS_FAILURE; + } /* rewrite request URI to point to the real host */ /* i still holds the valid index into the URLMAP table */ @@ -152,9 +157,10 @@ int proxy_request (sip_t *request) { } /* add my Via header line (inbound interface)*/ - sts = proxy_add_myvia(request, 1); + sts = sip_add_myvia(request, IF_INBOUND); if (sts == STS_FAILURE) { - WARN("adding my inbound via failed!"); + ERROR("adding my inbound via failed!"); + return STS_FAILURE; } /* if this is CANCEL/BYE request, stop RTP proxying */ @@ -171,7 +177,14 @@ int proxy_request (sip_t *request) { case REQTYP_OUTGOING: /* get destination address */ url=msg_geturi(request); + sts = get_ip_by_host(url->host, &sendto_addr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "proxy_request: cannot resolve URI [%s]", + url->host); + return STS_FAILURE; + } + /* if it is addressed to myself, then it must be some request * method that I as a proxy do not support. Reject */ if (is_sipuri_local(request) == STS_TRUE) { @@ -182,12 +195,11 @@ int proxy_request (sip_t *request) { url->username? url->username : "*NULL*", url->host? url->host : "*NULL*"); - proxy_gen_response(request, 403 /*forbidden*/); + sip_gen_response(request, 403 /*forbidden*/); return STS_FAILURE; } - /* if an INVITE, rewrite body */ if (MSG_IS_INVITE(request)) { sts = proxy_rewrite_invitation_body(request); @@ -219,7 +231,7 @@ int proxy_request (sip_t *request) { } /* add my Via header line (outbound interface)*/ - sts = proxy_add_myvia(request, 0); + sts = sip_add_myvia(request, IF_OUTBOUND); if (sts == STS_FAILURE) { ERROR("adding my outbound via failed!"); } @@ -233,8 +245,8 @@ int proxy_request (sip_t *request) { default: url=msg_geturi(request); - DEBUGC(DBCLASS_PROXY,"proxy_request: refused to proxy"); - WARN("request [%s] from/to unregistered UA (RQ: %s@%s -> %s@%s)", + DEBUGC(DBCLASS_PROXY, "request [%s] from/to unregistered UA " + "(RQ: %s@%s -> %s@%s)", request->strtline->sipmethod? request->strtline->sipmethod:"*NULL*", request->from->url->username? request->from->url->username:"*NULL*", request->from->url->host? request->from->url->host : "*NULL*", @@ -242,12 +254,18 @@ int proxy_request (sip_t *request) { url->host? url->host : "*NULL*"); /* - * if we end up here, we deal with a request that we have - * no proxy entry - so it must be ment to be for the proxy itself. - * As we only deal with REGISTER requests, we will anser this one - * with FORBIDDEN + * we may end up here for two reasons: + * 1) An incomming request (from outbound) that is directed to + * an unknown (not registered) local UA + * 2) an outgoing request from a local UA that is not registered. + * + * Case 1) we should probably answer with "404 Not Found", + * case 2) more likely a "403 Forbidden" + * + * How about "408 Request Timeout" ? + * */ - proxy_gen_response(request, 403 /*forbidden*/); + sip_gen_response(request, 408 /* Request Timeout */); return STS_FAILURE; } @@ -304,7 +322,7 @@ int proxy_response (sip_t *response) { } /* ALWAYS: remove my Via header line */ - sts = proxy_del_myvia(response); + sts = sip_del_myvia(response); if (sts == STS_FAILURE) { DEBUGC(DBCLASS_PROXY,"not addressed to my VIA, ignoring response"); return STS_FAILURE; @@ -394,8 +412,7 @@ int proxy_response (sip_t *response) { break; default: - DEBUGC(DBCLASS_PROXY,"proxy_response: refused to proxy"); - WARN("response from/to unregistered UA (%s@%s)", + DEBUGC(DBCLASS_PROXY, "response from/to unregistered UA (%s@%s)", response->from->url->username? response->from->url->username:"*NULL*", response->from->url->host? response->from->url->host : "*NULL*"); return STS_FAILURE; @@ -409,6 +426,11 @@ int proxy_response (sip_t *response) { } sts = get_ip_by_host(via->host, &addr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "proxy_response: cannot resolve via [%s]", + via->host); + return STS_FAILURE; + } sts = msg_2char(response, &buffer); if (sts != 0) { @@ -429,147 +451,6 @@ int proxy_response (sip_t *response) { } -/* - * PROXY_GEN_RESPONSE - * - * send an proxy generated response back to the client. - * Only errors are reported from the proxy itself. - * code = SIP result code to deliver - * - * RETURNS - * STS_SUCCESS on success - * STS_FAILURE on error - */ -int proxy_gen_response(sip_t *request, int code) { - sip_t *response; - int sts; - via_t *via; - int port; - char *buffer; - struct in_addr addr; - - /* create the response template */ - if ((response=msg_make_template_reply(request, code))==NULL) { - ERROR("proxy_response: error in msg_make_template_reply"); - return STS_FAILURE; - } - - /* we must check if first via has x.x.x.x address. If not, we must resolve it */ - msg_getvia (response, 0, &via); - if (via == NULL) - { - ERROR("proxy_response: Cannot send response - no via field"); - return STS_FAILURE; - } - - -/* name resolution */ - if (inet_aton (via->host,&addr) == 0) - { - /* need name resolution */ - DEBUGC(DBCLASS_DNS,"resolving name:%s",via->host); - sts = get_ip_by_host(via->host, &addr); - } - -DEBUGC(DBCLASS_PROXY,"response=%p",response); - sts = msg_2char(response, &buffer); - if (sts != 0) { - ERROR("proxy_response: msg_2char failed"); - return STS_FAILURE; - } - - - if (via->port) { - port=atoi(via->port); - } else { - port=SIP_PORT; - } - - /* send to destination */ - sipsock_send_udp(&sip_socket, addr, port, - buffer, strlen(buffer), 1); - - /* free the resources */ - msg_free(response); - free(response); - free (buffer); - return STS_SUCCESS; -} - - -/* - * PROXY_ADD_MYVIA - * - * interface == 0 -> outbound interface, else inbound interface - * - * RETURNS - * STS_SUCCESS on success - * STS_FAILURE on error - */ -int proxy_add_myvia (sip_t *request, int interface) { - struct in_addr addr; - char tmp[URL_STRING_SIZE]; - via_t *via; - int sts; - - if (interface == 0) { - sts = get_ip_by_ifname(configuration.outbound_if, &addr); - if (sts == STS_FAILURE) { - ERROR("can't find outbound interface %s - configuration error?", - configuration.outbound_if); - return STS_FAILURE; - } - } else { - sts = get_ip_by_ifname(configuration.inbound_if, &addr); - if (sts == STS_FAILURE) { - ERROR("can't find inbound interface %s - configuration error?", - configuration.inbound_if); - return STS_FAILURE; - } - } - - sprintf(tmp, "SIP/2.0/UDP %s:%i", inet_ntoa(addr), - configuration.sip_listen_port); - DEBUGC(DBCLASS_BABBLE,"adding VIA:%s",tmp); - - sts = via_init(&via); - if (sts!=0) return STS_FAILURE; /* allocation failed */ - - sts = via_parse(via, tmp); - if (sts!=0) return STS_FAILURE; - - list_add(request->vias,via,0); - - return STS_SUCCESS; -} - - -/* - * PROXY_DEL_MYVIA - * - * RETURNS - * STS_SUCCESS on success - * STS_FAILURE on error - */ -int proxy_del_myvia (sip_t *response) { - via_t *via; - int sts; - - DEBUGC(DBCLASS_PROXY,"deleting topmost VIA"); - via = list_get (response->vias, 0); - - if ( is_via_local(via) == STS_FALSE ) { - ERROR("I'm trying to delete a VIA but it's not mine! host=%s",via->host); - return STS_FAILURE; - } - - sts = list_remove(response->vias, 0); - via_free (via); - free(via); - return STS_SUCCESS; -} - - /* * PROXY_REWRITE_INVITATION_BODY * @@ -619,6 +500,12 @@ int proxy_rewrite_invitation_body(sip_t *mymsg){ * start forwarding for each media stream ('m=' item in SIP message) */ sts = get_ip_by_host(sdp_c_addr_get(sdp,-1,0), &lcl_clnt_addr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "proxy_rewrite_invitation_body: cannot resolve " + "m= (media) host [%s]", sdp_c_addr_get(sdp,-1,0)); + return STS_FAILURE; + } + sts = get_ip_by_ifname(configuration.outbound_if, &outb_addr); if (sts == STS_FAILURE) { ERROR("can't find outbound interface %s - configuration error?", diff --git a/src/register.c b/src/register.c index 52d81ad..743e41d 100644 --- a/src/register.c +++ b/src/register.c @@ -112,15 +112,19 @@ int register_client(sip_t *my_msg) { expires=600; msg_setexpires(my_msg, "600"); } - DEBUGC(DBCLASS_REG,"expires:%i seconds",expires); + url1_to=my_msg->to->url; + url1_contact=((contact_t*)(my_msg->contacts->node->element))->url; + + DEBUGC(DBCLASS_REG,"register: %s@%s expires=%i seconds", + (url1_contact->username) ? url1_contact->username : "*NULL*", + (url1_contact->host) ? url1_contact->host : "*NULL*", + expires); /* Update registration. There are two possibilities: * - already registered, then update the existing record * - not registered, then create a new record */ - url1_to=my_msg->to->url; - url1_contact=((contact_t*)(my_msg->contacts->node->element))->url; j=-1; for (i=0; i %s@%s at " + "slot=%i, exp=%li", (url1_contact->username) ? url1_contact->username : "*NULL*", (url1_contact->host) ? url1_contact->host : "*NULL*", + (url2_to->username) ? url2_to->username : "*NULL*", + (url2_to->host) ? url2_to->host : "*NULL*", i, urlmap[i].expires-time_now); break; } @@ -151,10 +158,6 @@ int register_client(sip_t *my_msg) { if (i >= URLMAP_SIZE) { /* entry not existing, create new one */ i=j; - DEBUGC(DBCLASS_REG,"create new entry for %s@%s at slot=%i", - (url1_contact->username) ? url1_contact->username : "*NULL*", - (url1_contact->host) ? url1_contact->host : "*NULL*", - i); /* write entry */ urlmap[i].active=1; @@ -163,6 +166,13 @@ int register_client(sip_t *my_msg) { url_clone( my_msg->to->url, &urlmap[i].reg_url); /* To: field */ + DEBUGC(DBCLASS_REG,"create new entry for %s@%s <-> %s@%s at slot=%i", + (url1_contact->username) ? url1_contact->username : "*NULL*", + (url1_contact->host) ? url1_contact->host : "*NULL*", + (urlmap[i].reg_url->username) ? urlmap[i].reg_url->username : "*NULL*", + (urlmap[i].reg_url->host) ? urlmap[i].reg_url->host : "*NULL*", + i); + /* * try to figure out if we ought to do some masquerading */ @@ -197,10 +207,10 @@ int register_client(sip_t *my_msg) { via_clone( ((via_t*)(my_msg->vias->node->element)), &urlmap[i].via); /* via field */ - } + } /* if new entry */ /* give some safety margin for the next update */ - if (expires >0) expires+=30; + if (expires > 0) expires+=30; /* update registration timeout */ urlmap[i].expires=time_now+expires; @@ -304,6 +314,11 @@ int register_response(sip_t *request, int flag) { if (inet_aton (via->host,&addr) == 0) { /* yes, get IP address */ sts = get_ip_by_host(via->host, &addr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_REG, "register_response: cannot resolve VIA [%s]", + via->host); + return STS_FAILURE; + } } sts = msg_2char(response, &buffer); diff --git a/src/rtpproxy.c b/src/rtpproxy.c index fe9f803..5ca7639 100644 --- a/src/rtpproxy.c +++ b/src/rtpproxy.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,10 @@ #include "siproxd.h" #include "log.h" +static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\ + BUILDSTR " $"; + + /* configuration storage */ extern struct siproxd_config configuration; @@ -64,7 +69,7 @@ struct { /* thread id of RTP proxy */ -pthread_t rtpproxy_tid; +pthread_t rtpproxy_tid=0; /* master fd_set */ fd_set master_fdset; @@ -165,7 +170,7 @@ void *rtpproxy_main(void *arg) { num_fd--; } - } + } /* for i */ /* age and clean rtp_proxytable */ @@ -177,8 +182,9 @@ void *rtpproxy_main(void *arg) { /* time one has expired, clean it up */ callid.number=rtp_proxytable[i].callid_number; callid.host=rtp_proxytable[i].callid_host; - DEBUGC(DBCLASS_RTP,"RTP stream %s@%s (idx=%i) has expired", - callid.number, callid.host, i); + DEBUGC(DBCLASS_RTP,"RTP stream sock=%i %s@%s (idx=%i) " + "has expired", rtp_proxytable[i].sock, + callid.number, callid.host, i); rtp_stop_fwd(&callid, 1); /* don't lock the mutex, as we own the lock already here */ } @@ -305,7 +311,7 @@ int rtp_start_fwd (call_id_t *callid, int media_stream_no, /* port is available, try to allocate */ if (j == RTPPROXY_SIZE) { port=i; - sock=sockbind(outbound_ipaddr, port); + sock=sockbind(outbound_ipaddr, port, 0); /* if success break, else try further on */ if (sock) break; } @@ -384,8 +390,8 @@ unlock_and_exit: * STS_FAILURE on error */ int rtp_stop_fwd (call_id_t *callid, int nolock) { - int i; - int sts=STS_SUCCESS; + int i, sts; + int retsts=STS_SUCCESS; int got_match=0; if (configuration.rtp_proxy_enable == 0) return STS_SUCCESS; @@ -426,7 +432,20 @@ int rtp_stop_fwd (call_id_t *callid, int nolock) { (strcmp(rtp_proxytable[i].callid_host, callid->host)==0) ) { /* match: close socket and clean slot in rtp_proxytable */ - close(rtp_proxytable[i].sock); + sts = close(rtp_proxytable[i].sock); + if (sts < 0) { + ERROR("Error in close(%i): %s\n", rtp_proxytable[i].sock, + strerror(errno)); + } + + DEBUGC(DBCLASS_RTP,"closing socket %i for RTP stream " + "%s:%s == %s:%s (idx=%i) sts=%i", + rtp_proxytable[i].sock, + rtp_proxytable[i].callid_number, + rtp_proxytable[i].callid_host, + callid->number, + callid->host, + i, sts); memset(&rtp_proxytable[i], 0, sizeof(rtp_proxytable[0])); got_match=1; } @@ -437,7 +456,7 @@ int rtp_stop_fwd (call_id_t *callid, int nolock) { if (!got_match) { DEBUGC(DBCLASS_RTP,"rtp_stop_fwd: can't find active stream for %s@%s", callid->number, callid->host); - sts = STS_FAILURE; + retsts = STS_FAILURE; goto unlock_and_exit; } @@ -460,7 +479,7 @@ unlock_and_exit: } #undef return - return sts; + return retsts; } @@ -487,3 +506,21 @@ int rtp_recreate_fdset(void) { return STS_SUCCESS; } + +/* + * kills the rtp_proxy thread + * + * RETURNS + * - + */ +void rtpproxy_kill( void ) { + void *thread_status; + + if (rtpproxy_tid) { + pthread_cancel(rtpproxy_tid); + pthread_join(rtpproxy_tid, &thread_status); + } + + DEBUGC(DBCLASS_RTP,"killed RTP proxy thread"); + return; +} diff --git a/src/security.c b/src/security.c index 73113a4..6860575 100644 --- a/src/security.c +++ b/src/security.c @@ -37,6 +37,10 @@ #include "log.h" +static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\ + BUILDSTR " $"; + + /* * do security and integrity checks on the received packet * (raw buffer) diff --git a/src/sip_utils.c b/src/sip_utils.c index 3e9b9a3..27f6076 100644 --- a/src/sip_utils.c +++ b/src/sip_utils.c @@ -54,6 +54,7 @@ static char const ident[]="$Id: " __FILE__ ": " PACKAGE "-" VERSION "-"\ extern struct siproxd_config configuration; extern int h_errno; +extern int sip_socket; /* sending SIP datagrams */ /* @@ -174,7 +175,12 @@ int is_via_local (via_t *via) { DEBUGC(DBCLASS_BABBLE,"via name %s",via->host); if (inet_aton(via->host,&addr_via) == 0) { /* need name resolution */ - get_ip_by_host(via->host, &addr_via); + sts=get_ip_by_host(via->host, &addr_via); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_DNS, "is_via_local: cannot resolve VIA [%s]", + via->host); + return STS_FAILURE; + } } found=0; @@ -233,14 +239,26 @@ int compare_url(url_t *url1, url_t *url2) { } /* get the IP addresses from the (possible) hostnames */ - get_ip_by_host(url1->host, &addr1); - get_ip_by_host(url2->host, &addr2); + sts=get_ip_by_host(url1->host, &addr1); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "compare_url: cannot resolve host [%s]", + url1->host); + return STS_FAILURE; + } + + sts=get_ip_by_host(url2->host, &addr2); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "compare_url: cannot resolve host [%s]", + url2->host); + return STS_FAILURE; + } /* Broken(?) MSN messenger - does not supply a user name part. So we simply compare the host part then */ if ((url1->username == NULL) || (url2->username == NULL)) { - WARN("compare_url: NULL username pointer: MSN messenger is known to " - "trigger this one!"); +// let's be nice to Billy boy and don't complain evey time ;-) +// WARN("compare_url: NULL username pointer: MSN messenger is known to " +// "trigger this one!"); DEBUGC(DBCLASS_DNS, "comparing broken urls (no user): " "%s[%s] -> %s[%s]", url1->host, inet_ntoa(addr1), url2->host, inet_ntoa(addr2)); @@ -402,3 +420,148 @@ int check_rewrite_rq_uri (sip_t *sip) { } +/* + * PROXY_GEN_RESPONSE + * + * send an proxy generated response back to the client. + * Only errors are reported from the proxy itself. + * code = SIP result code to deliver + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error + */ +int sip_gen_response(sip_t *request, int code) { + sip_t *response; + int sts; + via_t *via; + int port; + char *buffer; + struct in_addr addr; + + /* create the response template */ + if ((response=msg_make_template_reply(request, code))==NULL) { + ERROR("proxy_response: error in msg_make_template_reply"); + return STS_FAILURE; + } + + /* we must check if first via has x.x.x.x address. If not, we must resolve it */ + msg_getvia (response, 0, &via); + if (via == NULL) + { + ERROR("proxy_response: Cannot send response - no via field"); + return STS_FAILURE; + } + + + /* name resolution */ + if (inet_aton(via->host, &addr) == 0) + { + /* need name resolution */ + DEBUGC(DBCLASS_DNS,"resolving name:%s",via->host); + sts = get_ip_by_host(via->host, &addr); + if (sts == STS_FAILURE) { + DEBUGC(DBCLASS_PROXY, "sip_gen_response: cannot resolve via [%s]", + via->host); + return STS_FAILURE; + } + } + + sts = msg_2char(response, &buffer); + if (sts != 0) { + ERROR("proxy_response: msg_2char failed"); + return STS_FAILURE; + } + + + if (via->port) { + port=atoi(via->port); + } else { + port=SIP_PORT; + } + + /* send to destination */ + sipsock_send_udp(&sip_socket, addr, port, + buffer, strlen(buffer), 1); + + /* free the resources */ + msg_free(response); + free(response); + free (buffer); + return STS_SUCCESS; +} + + +/* + * PROXY_ADD_MYVIA + * + * interface == IF_OUTBOUND, IF_INBOUND + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error + */ +int sip_add_myvia (sip_t *request, int interface) { + struct in_addr addr; + char tmp[URL_STRING_SIZE]; + via_t *via; + int sts; + + if (interface == IF_OUTBOUND) { + sts = get_ip_by_ifname(configuration.outbound_if, &addr); + if (sts == STS_FAILURE) { + ERROR("can't find outbound interface %s - configuration error?", + configuration.outbound_if); + return STS_FAILURE; + } + } else { + sts = get_ip_by_ifname(configuration.inbound_if, &addr); + if (sts == STS_FAILURE) { + ERROR("can't find inbound interface %s - configuration error?", + configuration.inbound_if); + return STS_FAILURE; + } + } + + sprintf(tmp, "SIP/2.0/UDP %s:%i", inet_ntoa(addr), + configuration.sip_listen_port); + DEBUGC(DBCLASS_BABBLE,"adding VIA:%s",tmp); + + sts = via_init(&via); + if (sts!=0) return STS_FAILURE; /* allocation failed */ + + sts = via_parse(via, tmp); + if (sts!=0) return STS_FAILURE; + + list_add(request->vias,via,0); + + return STS_SUCCESS; +} + + +/* + * PROXY_DEL_MYVIA + * + * RETURNS + * STS_SUCCESS on success + * STS_FAILURE on error + */ +int sip_del_myvia (sip_t *response) { + via_t *via; + int sts; + + DEBUGC(DBCLASS_PROXY,"deleting topmost VIA"); + via = list_get (response->vias, 0); + + if ( is_via_local(via) == STS_FALSE ) { + ERROR("I'm trying to delete a VIA but it's not mine! host=%s",via->host); + return STS_FAILURE; + } + + sts = list_remove(response->vias, 0); + via_free (via); + free(via); + return STS_SUCCESS; +} + + diff --git a/src/siproxd.c b/src/siproxd.c index 25aee05..8cfeab6 100644 --- a/src/siproxd.c +++ b/src/siproxd.c @@ -129,6 +129,10 @@ int main (int argc, char *argv[]) /* * Init stuff */ + + /* cancel RTP thread at exit */ + atexit(rtpproxy_kill); + /* read the config file */ if (read_config(configfile, config_search) == STS_FAILURE) exit(1); @@ -225,7 +229,10 @@ int main (int argc, char *argv[]) (my_msg->strtline->sipmethod)? my_msg->strtline->sipmethod : "NULL") ; - /* if RQ REGISTER, just register and send an answer */ + /* + * 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); @@ -235,9 +242,24 @@ int main (int argc, char *argv[]) inet_ntoa(from.sin_addr)); } - /* MSG is a request, add current via entry, + /* + * check if outbound interface is UP. + * If not, send back error to UA and + * skip any proxying attempt + */ + } else if (get_ip_by_ifname(configuration.outbound_if,NULL) != + STS_SUCCESS) { + DEBUGC(DBCLASS_SIP, "got a %s to proxy, but outbound interface " + "is down", (MSG_IS_REQUEST(my_msg))? "REQ" : "RES"); + + if (MSG_IS_REQUEST(my_msg)) + sip_gen_response(my_msg, 408 /*request timeout*/); + + /* + * MSG is a request, add current via entry, * do a lookup in the URLMAP table and - * send to the final destination */ + * send to the final destination + */ } else if (MSG_IS_REQUEST(my_msg)) { if (access & ACCESSCTL_SIP) { sts = proxy_request(my_msg); @@ -246,8 +268,10 @@ int main (int argc, char *argv[]) inet_ntoa(from.sin_addr)); } - /* MSG is a response, remove current via and - * send to next via in chain */ + /* + * MSG is a response, remove current via and + * send to the next VIA in chain + */ } else if (MSG_IS_RESPONSE(my_msg)) { if (access & ACCESSCTL_SIP) { sts = proxy_response(my_msg); @@ -256,7 +280,9 @@ int main (int argc, char *argv[]) inet_ntoa(from.sin_addr)); } - /* unsupported message */ + /* + * unsupported message + */ } else { ERROR("received unsupported SIP type %s %s", (MSG_IS_REQUEST(my_msg))? "REQ" : "RES", diff --git a/src/siproxd.h b/src/siproxd.h index 531aec6..07c2f98 100644 --- a/src/siproxd.h +++ b/src/siproxd.h @@ -26,7 +26,7 @@ int sipsock_wait(void); int sipsock_read(void *buf, size_t bufsize, struct sockaddr_in *from); int sipsock_send_udp(int *sock, struct in_addr addr, int port, /*X*/ char *buffer, int size, int allowdump); -int sockbind(struct in_addr ipaddr, int localport); +int sockbind(struct in_addr ipaddr, int localport, int errflg); /* register.c */ void register_init(void); @@ -37,9 +37,6 @@ int register_response(sip_t *request, int flag); /*X*/ /* proxy.c */ int proxy_request (sip_t *request); /*X*/ int proxy_response (sip_t *response); /*X*/ -int proxy_gen_response(sip_t *request, int code); /*X*/ -int proxy_add_myvia (sip_t *request, int interface); /*X*/ -int proxy_del_myvia (sip_t *response); /*X*/ int proxy_rewrite_invitation_body(sip_t *mymsg); /*X*/ int proxy_rewrite_request_uri(sip_t *mymsg, int idx); /*X*/ @@ -55,16 +52,22 @@ int is_via_local (via_t *via); /*X*/ int compare_url(url_t *url1, url_t *url2); /*X*/ int is_sipuri_local (sip_t *sip); /*X*/ int check_rewrite_rq_uri (sip_t *sip); /*X*/ +int sip_gen_response(sip_t *request, int code); /*X*/ +#define IF_OUTBOUND 0 +#define IF_INBOUND 1 +int sip_add_myvia (sip_t *request, int interface); /*X*/ +int sip_del_myvia (sip_t *response); /*X*/ /* readconf.c */ int read_config(char *name, int search); /*X*/ /* rtpproxy.c */ -int rtpproxy_init( void ); /*X*/ -int rtp_start_fwd (call_id_t *callid, int media_stream_no, /*X*/ - struct in_addr outbound_ipaddr, int *outboundport, - struct in_addr lcl_client_ipaddr, int lcl_clientport); -int rtp_stop_fwd (call_id_t *callid, int nolock); /*X*/ +int rtpproxy_init( void ); /*X*/ +int rtp_start_fwd (call_id_t *callid, int media_stream_no, /*X*/ + struct in_addr outbound_ipaddr, int *outboundport, + struct in_addr lcl_client_ipaddr, int lcl_clientport); +int rtp_stop_fwd (call_id_t *callid, int nolock); /*X*/ +void rtpproxy_kill( void ); /*X*/ /* accessctl.c */ int accesslist_check(struct sockaddr_in from); @@ -144,6 +147,9 @@ struct siproxd_config { #define STATUSCODE_SIZE 5 /* size of string representation of status */ #define DNS_CACHE_SIZE 32 /* number of entries in internal DNS cache */ #define DNS_MAX_AGE 60 /* maximum age of an cache entry (sec) */ +#define IFADR_CACHE_SIZE 32 /* number of entries in internal IFADR cache */ +#define IFADR_MAX_AGE 5 /* max. age of the IF address cache (sec) */ +#define IFNAME_SIZE 16 /* max string length of a interface name */ #define HOSTNAME_SIZE 64 /* max string length of a hostname */ #define USERNAME_SIZE 64 /* max string length of a username (auth) */ #define PASSWORD_SIZE 64 /* max string length of a password (auth) */ diff --git a/src/sock.c b/src/sock.c index 5239825..839f94f 100644 --- a/src/sock.c +++ b/src/sock.c @@ -61,8 +61,8 @@ int sipsock_listen (void) { struct in_addr ipaddr; memset(&ipaddr, 0, sizeof(struct in_addr)); - listen_socket=sockbind(ipaddr, configuration.sip_listen_port); - if (listen_socket==0) return STS_FAILURE; /* failure*/ + listen_socket=sockbind(ipaddr, configuration.sip_listen_port, 1); + if (listen_socket == 0) return STS_FAILURE; /* failure*/ INFO("listening on port %i", configuration.sip_listen_port); DEBUGC(DBCLASS_NET,"bound listen socket %i",listen_socket); @@ -127,7 +127,7 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, /* first time: allocate a socket for sending */ if (*sock == 0) { *sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (*sock == 0) { + if (*sock < 0) { ERROR("socket() call failed:%s",strerror(errno)); return STS_FAILURE; } @@ -154,7 +154,8 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, if (sts == -1) { if (errno != ECONNREFUSED) { - ERROR("sendto() call failed: %s",strerror(errno)); + ERROR("sendto() [%s] call failed: %s",inet_ntoa(addr), + strerror(errno)); return STS_FAILURE; } DEBUGC(DBCLASS_BABBLE,"sendto() call failed:%s",strerror(errno)); @@ -168,27 +169,28 @@ int sipsock_send_udp(int *sock, struct in_addr addr, int port, /* * generic routine to allocate and bind a socket to a specified * local address and port (UDP) + * errflg !=0 log errors, ==0 don't * * RETURNS socket number on success, zero on failure */ -int sockbind(struct in_addr ipaddr, int localport) { +int sockbind(struct in_addr ipaddr, int localport, int errflg) { struct sockaddr_in my_addr; int sts; int sock; my_addr.sin_family = AF_INET; memcpy(&my_addr.sin_addr.s_addr, &ipaddr, sizeof(struct in_addr)); - my_addr.sin_port= htons(localport); + my_addr.sin_port = htons(localport); sock=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock == 0) { + if (sock < 0) { ERROR("socket() call failed:%s",strerror(errno)); return 0; } sts=bind(sock, (struct sockaddr *)&my_addr, sizeof(my_addr)); if (sts != 0) { - ERROR("bind failed:%s",strerror(errno)); + if (errflg) ERROR("bind failed:%s",strerror(errno)); close(sock); return 0; } diff --git a/src/utils.c b/src/utils.c index b383c07..972a5db 100644 --- a/src/utils.c +++ b/src/utils.c @@ -68,7 +68,7 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { static struct { time_t timestamp; struct in_addr addr; - char hostname[HOSTNAME_SIZE]; + char hostname[HOSTNAME_SIZE+1]; } dns_cache[DNS_CACHE_SIZE]; static int cache_initialized=0; @@ -116,11 +116,22 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { hostentry=gethostbyname(hostname); if (hostentry==NULL) { + if (h_errno == HOST_NOT_FOUND) { + /* this is actually not really an error */ #ifdef HAVE_HSTRERROR - ERROR("gethostbyname(%s) failed: %s",hostname,hstrerror(h_errno)); + DEBUGC(DBCLASS_DNS, "gethostbyname(%s) failed: %s", + hostname, hstrerror(h_errno)); #else - ERROR("gethostbyname(%s) failed: h_errno=%i",hostname,h_errno); + DEBUGC(DBCLASS_DNS, "gethostbyname(%s) failed: h_errno=%i", + hostname, h_errno); #endif + } else { +#ifdef HAVE_HSTRERROR + ERROR("gethostbyname(%s) failed: %s",hostname, hstrerror(h_errno)); +#else + ERROR("gethostbyname(%s) failed: h_errno=%i",hostname, h_errno); +#endif + } return STS_FAILURE; } @@ -129,9 +140,8 @@ int get_ip_by_host(char *hostname, struct in_addr *addr) { hostname, inet_ntoa(*addr)); /* - * remember the result in the cache + * find an empty slot in the cache */ - /* find an empty slot */ j=0; for (i=0; i= DNS_CACHE_SIZE) i=j; - /* store in cache */ + /* + * store the result in the cache + */ DEBUGC(DBCLASS_DNS, "DNS lookup - store into cache, entry %i)", i); memset(&dns_cache[i], 0, sizeof(dns_cache[0])); strncpy(dns_cache[i].hostname, hostname, HOSTNAME_SIZE); @@ -216,11 +228,24 @@ void secure_enviroment (void) { /* * get_ip_by_ifname: * fetches own IP address by its interface name + * + * STS_SUCCESS on returning a valid IP and interface is UP + * STS_FAILURE if interface is DOWN or other problem */ int get_ip_by_ifname(char *ifname, struct in_addr *retaddr) { struct ifreq ifr; struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; int sockfd; + int i, j; + int ifflags, isup; + time_t t; + static struct { + time_t timestamp; + struct in_addr ifaddr; /* IP */ + int isup; /* interface is UP */ + char ifname[IFNAME_SIZE+1]; + } ifaddr_cache[IFADR_CACHE_SIZE]; + static int cache_initialized=0; if (ifname == NULL) { WARN("get_ip_by_ifname: got NULL ifname passed - please check config" @@ -228,6 +253,40 @@ int get_ip_by_ifname(char *ifname, struct in_addr *retaddr) { return STS_FAILURE; } + /* first time: initialize ifaddr cache */ + if (cache_initialized == 0) { + DEBUGC(DBCLASS_DNS, "initializing ifaddr cache (%i entries)", + IFADR_CACHE_SIZE); + memset(ifaddr_cache, 0, sizeof(ifaddr_cache)); + cache_initialized=1; + } + + time(&t); + /* clean expired entries */ + for (i=0; i %s %s", + ifname, inet_ntoa(ifaddr_cache[i].ifaddr), + (ifaddr_cache[i].isup)? "UP":"DOWN"); + return (ifaddr_cache[i].isup)? STS_SUCCESS: STS_FAILURE; + } /* if */ + } /* for i */ + + /* not found in cache, go and get it */ bzero(&ifr, sizeof(ifr)); if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { @@ -238,18 +297,57 @@ int get_ip_by_ifname(char *ifname, struct in_addr *retaddr) { strcpy(ifr.ifr_name, ifname); sin->sin_family = AF_INET; + /* get interface flags */ + if(ioctl(sockfd, SIOCGIFFLAGS, &ifr) != 0) { + ERROR("Error in ioctl SIOCGIFFLAGS: %s\n",strerror(errno)); + close(sockfd); + return STS_FAILURE; + } + ifflags=ifr.ifr_flags; + + /* get address */ if(ioctl(sockfd, SIOCGIFADDR, &ifr) != 0) { - ERROR("Error in ioctl: %s\n",strerror(errno)); + ERROR("Error in ioctl SIOCGIFADDR: %s\n",strerror(errno)); close(sockfd); return STS_FAILURE; } - DEBUGC(DBCLASS_DNS, "get_ip_by_ifname: interface %s has IP: %s", - ifname, inet_ntoa(sin->sin_addr)); + if (ifflags & IFF_UP) isup=1; + else isup=0; + + DEBUGC(DBCLASS_DNS, "get_ip_by_ifname: if %s has IP:%s (flags=%x) %s", + ifname, inet_ntoa(sin->sin_addr), ifflags, + (isup)? "UP":"DOWN"); + + /* + *find an empty slot in the cache + */ + j=0; + for (i=0; i= IFADR_CACHE_SIZE) i=j; + + /* + * store the result in the cache + */ + DEBUGC(DBCLASS_DNS, "ifname lookup - store into cache, entry %i)", i); + memset(&ifaddr_cache[i], 0, sizeof(ifaddr_cache[0])); + strncpy(ifaddr_cache[i].ifname, ifname, IFNAME_SIZE); + ifaddr_cache[i].timestamp=t; + memcpy(&ifaddr_cache[i].ifaddr, &sin->sin_addr, sizeof(sin->sin_addr)); + ifaddr_cache[i].isup=isup; + if (retaddr) memcpy(retaddr, &sin->sin_addr, sizeof(sin->sin_addr)); close(sockfd); - return STS_SUCCESS; + return (isup)? STS_SUCCESS : STS_FAILURE; }