2002-05-30 01:40:29 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-05-30 01:40:29 +00:00
*
2006-03-28 03:28:52 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
2002-05-30 01:40:29 +00:00
*
2005-07-19 23:17:02 +00:00
* Mark Spencer < markster @ digium . com >
2002-05-30 01:40:29 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2002-05-30 01:40:29 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief Various sorts of access control
2005-12-30 21:18:06 +00:00
*
2006-03-28 13:58:34 +00:00
* \ author Mark Spencer < markster @ digium . com >
2002-05-30 01:40:29 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2007-11-17 14:45:46 +00:00
# include "asterisk/network.h"
2008-01-22 20:42:47 +00:00
# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__Darwin__)
# include <fcntl.h>
# include <net/route.h>
# endif
2005-09-08 02:24:02 +00:00
# if defined(SOLARIS)
2004-12-14 23:36:30 +00:00
# include <sys/sockio.h>
2008-01-24 16:47:10 +00:00
# include <net/if.h>
2008-02-01 16:01:22 +00:00
# elif defined(HAVE_GETIFADDRS)
2008-01-24 16:47:10 +00:00
# include <ifaddrs.h>
2005-09-08 02:24:02 +00:00
# endif
2005-04-22 13:11:34 +00:00
# include "asterisk/acl.h"
# include "asterisk/channel.h"
# include "asterisk/utils.h"
# include "asterisk/lock.h"
# include "asterisk/srv.h"
2008-02-01 16:01:22 +00:00
# if (!defined(SOLARIS) && !defined(HAVE_GETIFADDRS))
2010-07-08 22:08:07 +00:00
static int get_local_address ( struct ast_sockaddr * ourip )
2008-02-01 16:01:22 +00:00
{
return - 1 ;
}
# else
2008-01-22 17:15:08 +00:00
static void score_address ( const struct sockaddr_in * sin , struct in_addr * best_addr , int * best_score )
{
const char * address ;
int score ;
address = ast_inet_ntoa ( sin - > sin_addr ) ;
/* RFC 1700 alias for the local network */
2009-03-04 20:48:42 +00:00
if ( address [ 0 ] = = ' 0 ' ) {
2008-01-22 17:15:08 +00:00
score = - 25 ;
/* RFC 1700 localnet */
2009-03-04 20:48:42 +00:00
} else if ( strncmp ( address , " 127 " , 3 ) = = 0 ) {
2008-01-22 17:15:08 +00:00
score = - 20 ;
/* RFC 1918 non-public address space */
2009-03-04 20:48:42 +00:00
} else if ( strncmp ( address , " 10. " , 3 ) = = 0 ) {
2008-01-22 17:15:08 +00:00
score = - 5 ;
/* RFC 1918 non-public address space */
2009-03-04 20:48:42 +00:00
} else if ( strncmp ( address , " 172 " , 3 ) = = 0 ) {
2008-01-22 17:15:08 +00:00
/* 172.16.0.0 - 172.19.255.255, but not 172.160.0.0 - 172.169.255.255 */
2009-03-04 20:48:42 +00:00
if ( address [ 4 ] = = ' 1 ' & & address [ 5 ] > = ' 6 ' & & address [ 6 ] = = ' . ' ) {
2008-01-22 17:15:08 +00:00
score = - 5 ;
/* 172.20.0.0 - 172.29.255.255, but not 172.200.0.0 - 172.255.255.255 nor 172.2.0.0 - 172.2.255.255 */
2009-03-04 20:48:42 +00:00
} else if ( address [ 4 ] = = ' 2 ' & & address [ 6 ] = = ' . ' ) {
2008-01-22 17:15:08 +00:00
score = - 5 ;
/* 172.30.0.0 - 172.31.255.255 */
2009-03-04 20:48:42 +00:00
} else if ( address [ 4 ] = = ' 3 ' & & address [ 5 ] < = ' 1 ' ) {
2008-01-22 17:15:08 +00:00
score = - 5 ;
/* All other 172 addresses are public */
2009-03-04 20:48:42 +00:00
} else {
2008-01-22 17:15:08 +00:00
score = 0 ;
2009-03-04 20:48:42 +00:00
}
/* RFC 2544 Benchmark test range (198.18.0.0 - 198.19.255.255, but not 198.180.0.0 - 198.199.255.255) */
} else if ( strncmp ( address , " 198.1 " , 5 ) = = 0 & & address [ 5 ] > = ' 8 ' & & address [ 6 ] = = ' . ' ) {
2008-01-22 17:15:08 +00:00
score = - 10 ;
/* RFC 1918 non-public address space */
2009-03-04 20:48:42 +00:00
} else if ( strncmp ( address , " 192.168 " , 7 ) = = 0 ) {
2008-01-22 17:15:08 +00:00
score = - 5 ;
/* RFC 3330 Zeroconf network */
2009-03-04 20:48:42 +00:00
} else if ( strncmp ( address , " 169.254 " , 7 ) = = 0 ) {
2008-01-22 17:15:08 +00:00
/*!\note Better score than a test network, but not quite as good as RFC 1918
* address space . The reason is that some Linux distributions automatically
* configure a Zeroconf address before trying DHCP , so we want to prefer a
* DHCP lease to a Zeroconf address .
*/
score = - 10 ;
/* RFC 3330 Test network */
2009-03-04 20:48:42 +00:00
} else if ( strncmp ( address , " 192.0.2. " , 8 ) = = 0 ) {
2008-01-22 17:15:08 +00:00
score = - 15 ;
/* Every other address should be publically routable */
2009-03-04 20:48:42 +00:00
} else {
2008-01-22 17:15:08 +00:00
score = 0 ;
2009-03-04 20:48:42 +00:00
}
2008-01-22 17:15:08 +00:00
if ( score > * best_score ) {
* best_score = score ;
memcpy ( best_addr , & sin - > sin_addr , sizeof ( * best_addr ) ) ;
}
}
2010-07-08 22:08:07 +00:00
static int get_local_address ( struct ast_sockaddr * ourip )
2008-01-22 17:15:08 +00:00
{
int s , res = - 1 ;
2008-01-22 20:42:47 +00:00
# ifdef SOLARIS
2008-01-22 17:15:08 +00:00
struct lifreq * ifr = NULL ;
struct lifnum ifn ;
struct lifconf ifc ;
struct sockaddr_in * sa ;
char * buf = NULL ;
int bufsz , x ;
2008-01-22 20:42:47 +00:00
# endif /* SOLARIS */
2010-08-15 13:08:45 +00:00
# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__) || defined(__GLIBC__)
2008-01-22 17:15:08 +00:00
struct ifaddrs * ifap , * ifaphead ;
int rtnerr ;
const struct sockaddr_in * sin ;
2008-01-22 20:42:47 +00:00
# endif /* BSD_OR_LINUX */
2008-01-24 16:47:10 +00:00
struct in_addr best_addr ;
2008-01-22 17:15:08 +00:00
int best_score = - 100 ;
2008-01-24 16:47:10 +00:00
memset ( & best_addr , 0 , sizeof ( best_addr ) ) ;
2008-01-22 17:15:08 +00:00
2010-08-15 13:08:45 +00:00
# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__) || defined(__GLIBC__)
2008-01-22 17:15:08 +00:00
rtnerr = getifaddrs ( & ifaphead ) ;
if ( rtnerr ) {
perror ( NULL ) ;
return - 1 ;
}
# endif /* BSD_OR_LINUX */
s = socket ( AF_INET , SOCK_STREAM , 0 ) ;
if ( s > 0 ) {
2010-08-15 13:08:45 +00:00
# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__) || defined(__GLIBC__)
2008-01-22 17:15:08 +00:00
for ( ifap = ifaphead ; ifap ; ifap = ifap - > ifa_next ) {
2008-03-27 19:26:45 +00:00
if ( ifap - > ifa_addr & & ifap - > ifa_addr - > sa_family = = AF_INET ) {
2008-01-22 17:15:08 +00:00
sin = ( const struct sockaddr_in * ) ifap - > ifa_addr ;
score_address ( sin , & best_addr , & best_score ) ;
res = 0 ;
2009-03-04 20:48:42 +00:00
if ( best_score = = 0 ) {
2008-01-22 17:15:08 +00:00
break ;
2009-03-04 20:48:42 +00:00
}
2008-01-22 17:15:08 +00:00
}
}
2008-01-22 20:42:47 +00:00
# endif /* BSD_OR_LINUX */
2008-01-22 17:15:08 +00:00
/* There is no reason whatsoever that this shouldn't work on Linux or BSD also. */
2008-01-22 20:42:47 +00:00
# ifdef SOLARIS
2008-01-22 17:15:08 +00:00
/* Get a count of interfaces on the machine */
ifn . lifn_family = AF_INET ;
ifn . lifn_flags = 0 ;
ifn . lifn_count = 0 ;
if ( ioctl ( s , SIOCGLIFNUM , & ifn ) < 0 ) {
close ( s ) ;
return - 1 ;
}
bufsz = ifn . lifn_count * sizeof ( struct lifreq ) ;
if ( ! ( buf = malloc ( bufsz ) ) ) {
close ( s ) ;
return - 1 ;
}
memset ( buf , 0 , bufsz ) ;
/* Get a list of interfaces on the machine */
ifc . lifc_len = bufsz ;
ifc . lifc_buf = buf ;
ifc . lifc_family = AF_INET ;
ifc . lifc_flags = 0 ;
if ( ioctl ( s , SIOCGLIFCONF , & ifc ) < 0 ) {
close ( s ) ;
free ( buf ) ;
return - 1 ;
}
2008-07-02 18:31:11 +00:00
for ( ifr = ifc . lifc_req , x = 0 ; x < ifn . lifn_count ; ifr + + , x + + ) {
2008-01-22 17:15:08 +00:00
sa = ( struct sockaddr_in * ) & ( ifr - > lifr_addr ) ;
2008-01-24 16:47:10 +00:00
score_address ( sa , & best_addr , & best_score ) ;
2008-01-22 17:15:08 +00:00
res = 0 ;
2009-03-04 20:48:42 +00:00
if ( best_score = = 0 ) {
2008-01-22 17:15:08 +00:00
break ;
2009-03-04 20:48:42 +00:00
}
2008-01-22 17:15:08 +00:00
}
free ( buf ) ;
2008-01-22 20:42:47 +00:00
# endif /* SOLARIS */
2009-03-04 20:48:42 +00:00
2008-01-22 17:15:08 +00:00
close ( s ) ;
}
2008-01-22 20:42:47 +00:00
# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__linux__) || defined(__Darwin__)
2008-01-22 17:15:08 +00:00
freeifaddrs ( ifaphead ) ;
2008-01-22 20:42:47 +00:00
# endif /* BSD_OR_LINUX */
2008-01-22 17:15:08 +00:00
2009-03-04 20:48:42 +00:00
if ( res = = 0 & & ourip ) {
2010-07-08 22:08:07 +00:00
ast_sockaddr_setnull ( ourip ) ;
ourip - > ss . ss_family = AF_INET ;
( ( struct sockaddr_in * ) & ourip - > ss ) - > sin_addr = best_addr ;
2009-03-04 20:48:42 +00:00
}
2008-01-22 17:15:08 +00:00
return res ;
}
2008-02-01 16:01:22 +00:00
# endif /* HAVE_GETIFADDRS */
2004-05-27 20:53:02 +00:00
/* Free HA structure */
2002-05-30 01:40:29 +00:00
void ast_free_ha ( struct ast_ha * ha )
{
struct ast_ha * hal ;
2006-07-10 19:05:48 +00:00
while ( ha ) {
2002-05-30 01:40:29 +00:00
hal = ha ;
ha = ha - > next ;
2007-06-06 21:20:11 +00:00
ast_free ( hal ) ;
2002-05-30 01:40:29 +00:00
}
}
2004-05-27 20:53:02 +00:00
/* Copy HA structure */
2009-09-03 16:31:54 +00:00
void ast_copy_ha ( const struct ast_ha * from , struct ast_ha * to )
2004-06-22 20:11:15 +00:00
{
2010-07-19 14:17:16 +00:00
ast_sockaddr_copy ( & to - > addr , & from - > addr ) ;
ast_sockaddr_copy ( & to - > netmask , & from - > netmask ) ;
2004-06-22 20:11:15 +00:00
to - > sense = from - > sense ;
}
2004-05-27 20:53:02 +00:00
/* Create duplicate of ha structure */
static struct ast_ha * ast_duplicate_ha ( struct ast_ha * original )
{
2006-02-14 22:28:01 +00:00
struct ast_ha * new_ha ;
2010-01-21 22:37:55 +00:00
if ( ( new_ha = ast_calloc ( 1 , sizeof ( * new_ha ) ) ) ) {
2006-02-14 22:28:01 +00:00
/* Copy from original to new object */
ast_copy_ha ( original , new_ha ) ;
}
2004-05-27 20:53:02 +00:00
2005-07-19 23:35:45 +00:00
return new_ha ;
2004-05-27 20:53:02 +00:00
}
/* Create duplicate HA link list */
/* Used in chan_sip2 templates */
struct ast_ha * ast_duplicate_ha_list ( struct ast_ha * original )
{
2006-07-10 19:05:48 +00:00
struct ast_ha * start = original ;
2004-05-27 20:53:02 +00:00
struct ast_ha * ret = NULL ;
2008-08-10 19:35:50 +00:00
struct ast_ha * current , * prev = NULL ;
2004-05-27 20:53:02 +00:00
2005-07-19 23:35:45 +00:00
while ( start ) {
2008-08-10 19:35:50 +00:00
current = ast_duplicate_ha ( start ) ; /* Create copy of this object */
2009-03-04 20:48:42 +00:00
if ( prev ) {
prev - > next = current ; /* Link previous to this object */
}
2004-05-27 20:53:02 +00:00
2009-03-04 20:48:42 +00:00
if ( ! ret ) {
ret = current ; /* Save starting point */
}
2004-05-27 20:53:02 +00:00
2009-03-04 20:48:42 +00:00
start = start - > next ; /* Go to next object */
prev = current ; /* Save pointer to this object */
2004-06-22 20:11:15 +00:00
}
2009-03-04 20:48:42 +00:00
return ret ; /* Return start of list */
2004-05-27 20:53:02 +00:00
}
2010-07-19 14:17:16 +00:00
/*!
* \ brief
* Isolate a 32 - bit section of an IPv6 address
*
* An IPv6 address can be divided into 4 32 - bit chunks . This gives
* easy access to one of these chunks .
*
* \ param sin6 A pointer to a struct sockaddr_in6
* \ param index Which 32 - bit chunk to operate on . Must be in the range 0 - 3.
*/
# define V6_WORD(sin6, index) ((uint32_t *)&((sin6)->sin6_addr))[(index)]
/*!
* \ brief
* Apply a netmask to an address and store the result in a separate structure .
*
* When dealing with IPv6 addresses , one cannot apply a netmask with a simple
* logical and operation . Furthermore , the incoming address may be an IPv4 address
* and need to be mapped properly before attempting to apply a rule .
*
* \ param addr The IP address to apply the mask to .
* \ param netmask The netmask configured in the host access rule .
* \ param result The resultant address after applying the netmask to the given address
* \ retval 0 Successfully applied netmask
* \ reval - 1 Failed to apply netmask
*/
static int apply_netmask ( const struct ast_sockaddr * addr , const struct ast_sockaddr * netmask ,
struct ast_sockaddr * result )
{
int res = 0 ;
if ( ast_sockaddr_is_ipv4 ( addr ) ) {
struct sockaddr_in result4 = { 0 , } ;
struct sockaddr_in * addr4 = ( struct sockaddr_in * ) & addr - > ss ;
struct sockaddr_in * mask4 = ( struct sockaddr_in * ) & netmask - > ss ;
result4 . sin_family = AF_INET ;
result4 . sin_addr . s_addr = addr4 - > sin_addr . s_addr & mask4 - > sin_addr . s_addr ;
ast_sockaddr_from_sin ( result , & result4 ) ;
} else if ( ast_sockaddr_is_ipv6 ( addr ) ) {
struct sockaddr_in6 result6 = { 0 , } ;
struct sockaddr_in6 * addr6 = ( struct sockaddr_in6 * ) & addr - > ss ;
struct sockaddr_in6 * mask6 = ( struct sockaddr_in6 * ) & netmask - > ss ;
int i ;
result6 . sin6_family = AF_INET6 ;
for ( i = 0 ; i < 4 ; + + i ) {
V6_WORD ( & result6 , i ) = V6_WORD ( addr6 , i ) & V6_WORD ( mask6 , i ) ;
}
memcpy ( & result - > ss , & result6 , sizeof ( result6 ) ) ;
result - > len = sizeof ( result6 ) ;
} else {
/* Unsupported address scheme */
res = - 1 ;
}
return res ;
}
/*!
* \ brief
* Parse a netmask in CIDR notation
*
* \ details
* For a mask of an IPv4 address , this should be a number between 0 and 32. For
* a mask of an IPv6 address , this should be a number between 0 and 128. This
* function creates an IPv6 ast_sockaddr from the given netmask . For masks of
* IPv4 addresses , this is accomplished by adding 96 to the original netmask .
*
* \ param [ out ] addr The ast_sockaddr produced from the CIDR netmask
* \ param is_v4 Tells if the address we are masking is IPv4 .
* \ param mask_str The CIDR mask to convert
* \ retval - 1 Failure
* \ retval 0 Success
*/
static int parse_cidr_mask ( struct ast_sockaddr * addr , int is_v4 , const char * mask_str )
{
int mask ;
if ( sscanf ( mask_str , " %30d " , & mask ) ! = 1 ) {
return - 1 ;
}
if ( is_v4 ) {
struct sockaddr_in sin ;
if ( mask < 0 | | mask > 32 ) {
return - 1 ;
}
memset ( & sin , 0 , sizeof ( sin ) ) ;
sin . sin_family = AF_INET ;
/* If mask is 0, then we already have the
* appropriate all 0 s address in sin from
* the above memset .
*/
if ( mask ! = 0 ) {
sin . sin_addr . s_addr = htonl ( 0xFFFFFFFF < < ( 32 - mask ) ) ;
}
ast_sockaddr_from_sin ( addr , & sin ) ;
} else {
struct sockaddr_in6 sin6 ;
int i ;
if ( mask < 0 | | mask > 128 ) {
return - 1 ;
}
memset ( & sin6 , 0 , sizeof ( sin6 ) ) ;
sin6 . sin6_family = AF_INET6 ;
for ( i = 0 ; i < 4 ; + + i ) {
/* Once mask reaches 0, we don't have
* to explicitly set anything anymore
* since sin6 was zeroed out already
*/
if ( mask > 0 ) {
V6_WORD ( & sin6 , i ) = htonl ( 0xFFFFFFFF < < ( mask < 32 ? ( 32 - mask ) : 0 ) ) ;
mask - = mask < 32 ? mask : 32 ;
}
}
memcpy ( & addr - > ss , & sin6 , sizeof ( sin6 ) ) ;
addr - > len = sizeof ( sin6 ) ;
}
return 0 ;
}
2007-11-14 13:18:40 +00:00
struct ast_ha * ast_append_ha ( const char * sense , const char * stuff , struct ast_ha * path , int * error )
2002-05-30 01:40:29 +00:00
{
2006-02-14 22:28:01 +00:00
struct ast_ha * ha ;
2002-05-30 01:40:29 +00:00
struct ast_ha * prev = NULL ;
struct ast_ha * ret ;
2007-10-22 13:36:13 +00:00
char * tmp = ast_strdupa ( stuff ) ;
2010-07-19 14:17:16 +00:00
char * address = NULL , * mask = NULL ;
int addr_is_v4 ;
2006-02-14 22:28:01 +00:00
2002-05-30 01:40:29 +00:00
ret = path ;
2005-07-19 23:35:45 +00:00
while ( path ) {
2002-05-30 01:40:29 +00:00
prev = path ;
path = path - > next ;
}
2007-10-18 07:23:41 +00:00
2010-01-21 22:37:55 +00:00
if ( ! ( ha = ast_calloc ( 1 , sizeof ( * ha ) ) ) ) {
2007-10-18 07:23:41 +00:00
return ret ;
2009-03-04 20:48:42 +00:00
}
2007-10-18 07:23:41 +00:00
2010-07-19 14:17:16 +00:00
address = strsep ( & tmp , " / " ) ;
if ( ! address ) {
address = tmp ;
2007-10-18 07:23:41 +00:00
} else {
2010-07-19 14:17:16 +00:00
mask = tmp ;
}
if ( ! ast_sockaddr_parse ( & ha - > addr , address , PARSE_PORT_FORBID ) ) {
ast_log ( LOG_WARNING , " Invalid IP address: %s \n " , address ) ;
ast_free_ha ( ha ) ;
* error = 1 ;
return ret ;
2002-05-30 01:40:29 +00:00
}
2007-10-18 07:23:41 +00:00
2010-07-19 14:17:16 +00:00
/* If someone specifies an IPv4-mapped IPv6 address,
* we just convert this to an IPv4 ACL
*/
if ( ast_sockaddr_ipv4_mapped ( & ha - > addr , & ha - > addr ) ) {
ast_log ( LOG_NOTICE , " IPv4-mapped ACL network address specified. "
" Converting to an IPv4 ACL network address. \n " ) ;
}
addr_is_v4 = ast_sockaddr_is_ipv4 ( & ha - > addr ) ;
if ( ! mask ) {
parse_cidr_mask ( & ha - > netmask , addr_is_v4 , addr_is_v4 ? " 32 " : " 128 " ) ;
} else if ( strchr ( mask , ' : ' ) | | strchr ( mask , ' . ' ) ) {
int mask_is_v4 ;
/* Mask is of x.x.x.x or x:x:x:x:x:x:x:x variety */
if ( ! ast_sockaddr_parse ( & ha - > netmask , mask , PARSE_PORT_FORBID ) ) {
ast_log ( LOG_WARNING , " Invalid netmask: %s \n " , mask ) ;
ast_free_ha ( ha ) ;
* error = 1 ;
return ret ;
}
/* If someone specifies an IPv4-mapped IPv6 netmask,
* we just convert this to an IPv4 ACL
*/
if ( ast_sockaddr_ipv4_mapped ( & ha - > netmask , & ha - > netmask ) ) {
ast_log ( LOG_NOTICE , " IPv4-mapped ACL netmask specified. "
" Converting to an IPv4 ACL netmask. \n " ) ;
}
mask_is_v4 = ast_sockaddr_is_ipv4 ( & ha - > netmask ) ;
if ( addr_is_v4 ^ mask_is_v4 ) {
ast_log ( LOG_WARNING , " Address and mask are not using same address scheme. \n " ) ;
ast_free_ha ( ha ) ;
2007-10-18 07:23:41 +00:00
* error = 1 ;
2010-07-19 14:17:16 +00:00
return ret ;
2009-03-04 20:48:42 +00:00
}
2010-07-19 14:17:16 +00:00
} else if ( parse_cidr_mask ( & ha - > netmask , addr_is_v4 , mask ) ) {
ast_log ( LOG_WARNING , " Invalid CIDR netmask: %s \n " , mask ) ;
ast_free_ha ( ha ) ;
* error = 1 ;
2007-10-18 07:23:41 +00:00
return ret ;
}
2010-07-19 14:17:16 +00:00
if ( apply_netmask ( & ha - > addr , & ha - > netmask , & ha - > addr ) ) {
/* This shouldn't happen because ast_sockaddr_parse would
* have failed much earlier on an unsupported address scheme
*/
char * failmask = ast_strdupa ( ast_sockaddr_stringify ( & ha - > netmask ) ) ;
char * failaddr = ast_strdupa ( ast_sockaddr_stringify ( & ha - > addr ) ) ;
ast_log ( LOG_WARNING , " Unable to apply netmask %s to address %s \n " , failmask , failaddr ) ;
ast_free_ha ( ha ) ;
* error = 1 ;
return ret ;
}
2007-10-18 07:23:41 +00:00
ha - > sense = strncasecmp ( sense , " p " , 1 ) ? AST_SENSE_DENY : AST_SENSE_ALLOW ;
ha - > next = NULL ;
if ( prev ) {
prev - > next = ha ;
} else {
ret = ha ;
}
2010-07-19 14:17:16 +00:00
ast_debug ( 1 , " %s/%s sense %d appended to acl for peer \n " , ast_strdupa ( ast_sockaddr_stringify ( & ha - > addr ) ) , ast_strdupa ( ast_sockaddr_stringify ( & ha - > netmask ) ) , ha - > sense ) ;
2007-10-18 07:23:41 +00:00
2003-05-05 06:14:25 +00:00
return ret ;
2002-05-30 01:40:29 +00:00
}
2010-07-19 14:17:16 +00:00
int ast_apply_ha ( const struct ast_ha * ha , const struct ast_sockaddr * addr )
2002-05-30 01:40:29 +00:00
{
/* Start optimistic */
int res = AST_SENSE_ALLOW ;
2010-07-19 14:17:16 +00:00
const struct ast_ha * current_ha ;
for ( current_ha = ha ; current_ha ; current_ha = current_ha - > next ) {
struct ast_sockaddr result ;
struct ast_sockaddr mapped_addr ;
const struct ast_sockaddr * addr_to_use ;
2007-07-19 12:38:13 +00:00
#if 0 /* debugging code */
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
char iabuf2 [ INET_ADDRSTRLEN ] ;
2004-05-27 20:53:02 +00:00
/* DEBUG */
2006-07-21 17:31:28 +00:00
ast_copy_string ( iabuf , ast_inet_ntoa ( sin - > sin_addr ) , sizeof ( iabuf ) ) ;
ast_copy_string ( iabuf2 , ast_inet_ntoa ( ha - > netaddr ) , sizeof ( iabuf2 ) ) ;
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " ##### Testing %s with %s \n " , iabuf , iabuf2 ) ;
2007-07-19 12:38:13 +00:00
# endif
2010-07-19 14:17:16 +00:00
if ( ast_sockaddr_is_ipv4 ( & ha - > addr ) ) {
if ( ast_sockaddr_is_ipv6 ( addr ) ) {
if ( ast_sockaddr_is_ipv4_mapped ( addr ) ) {
/* IPv4 ACLs apply to IPv4-mapped addresses */
ast_sockaddr_ipv4_mapped ( addr , & mapped_addr ) ;
addr_to_use = & mapped_addr ;
} else {
/* An IPv4 ACL does not apply to an IPv6 address */
continue ;
}
} else {
/* Address is IPv4 and ACL is IPv4. No biggie */
addr_to_use = addr ;
}
} else {
if ( ast_sockaddr_is_ipv6 ( addr ) & & ! ast_sockaddr_is_ipv4_mapped ( addr ) ) {
addr_to_use = addr ;
} else {
/* Address is IPv4 or IPv4 mapped but ACL is IPv6. Skip */
continue ;
}
}
2002-05-30 01:40:29 +00:00
/* For each rule, if this address and the netmask = the net address
apply the current rule */
2010-07-19 14:17:16 +00:00
if ( apply_netmask ( addr_to_use , & current_ha - > netmask , & result ) ) {
/* Unlikely to happen since we know the address to be IPv4 or IPv6 */
continue ;
}
if ( ! ast_sockaddr_cmp_addr ( & result , & current_ha - > addr ) ) {
res = current_ha - > sense ;
2009-03-04 20:48:42 +00:00
}
2002-05-30 01:40:29 +00:00
}
return res ;
}
2010-07-08 22:08:07 +00:00
static int resolve_first ( struct ast_sockaddr * addr , const char * name , int flag ,
int family )
{
struct ast_sockaddr * addrs ;
int addrs_cnt ;
addrs_cnt = ast_sockaddr_resolve ( & addrs , name , flag , family ) ;
if ( addrs_cnt > 0 ) {
if ( addrs_cnt > 1 ) {
ast_debug ( 1 , " Multiple addresses. Using the first only \n " ) ;
}
ast_sockaddr_copy ( addr , & addrs [ 0 ] ) ;
ast_free ( addrs ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lookup '%s' \n " , name ) ;
return - 1 ;
}
return 0 ;
}
int ast_get_ip_or_srv ( struct ast_sockaddr * addr , const char * value , const char * service )
2002-05-30 01:40:29 +00:00
{
2004-12-03 23:34:45 +00:00
char srv [ 256 ] ;
char host [ 256 ] ;
2010-07-08 22:08:07 +00:00
int srv_ret = 0 ;
int tportno ;
2004-12-03 23:34:45 +00:00
if ( service ) {
snprintf ( srv , sizeof ( srv ) , " %s.%s " , service , value ) ;
2010-07-08 22:08:07 +00:00
if ( ( srv_ret = ast_get_srv ( NULL , host , sizeof ( host ) , & tportno , srv ) ) > 0 ) {
2004-12-03 23:34:45 +00:00
value = host ;
}
}
2010-07-08 22:08:07 +00:00
if ( resolve_first ( addr , value , PARSE_PORT_FORBID , addr - > ss . ss_family ) ! = 0 ) {
2002-05-30 01:40:29 +00:00
return - 1 ;
}
2010-07-08 22:08:07 +00:00
if ( srv_ret > 0 ) {
ast_sockaddr_set_port ( addr , tportno ) ;
}
2002-05-30 01:40:29 +00:00
return 0 ;
}
2006-03-28 03:28:52 +00:00
struct dscp_codepoint {
char * name ;
unsigned int space ;
} ;
/* IANA registered DSCP codepoints */
static const struct dscp_codepoint dscp_pool1 [ ] = {
{ " CS0 " , 0x00 } ,
{ " CS1 " , 0x08 } ,
{ " CS2 " , 0x10 } ,
{ " CS3 " , 0x18 } ,
{ " CS4 " , 0x20 } ,
{ " CS5 " , 0x28 } ,
{ " CS6 " , 0x30 } ,
{ " CS7 " , 0x38 } ,
{ " AF11 " , 0x0A } ,
{ " AF12 " , 0x0C } ,
{ " AF13 " , 0x0E } ,
{ " AF21 " , 0x12 } ,
{ " AF22 " , 0x14 } ,
{ " AF23 " , 0x16 } ,
{ " AF31 " , 0x1A } ,
{ " AF32 " , 0x1C } ,
{ " AF33 " , 0x1E } ,
{ " AF41 " , 0x22 } ,
{ " AF42 " , 0x24 } ,
{ " AF43 " , 0x26 } ,
{ " EF " , 0x2E } ,
} ;
2007-04-30 16:16:26 +00:00
2009-03-04 20:48:42 +00:00
int ast_str2cos ( const char * value , unsigned int * cos )
2007-04-30 16:16:26 +00:00
{
int fval ;
2009-03-04 20:48:42 +00:00
2009-08-10 19:20:57 +00:00
if ( sscanf ( value , " %30d " , & fval ) = = 1 ) {
2007-04-30 16:16:26 +00:00
if ( fval < 8 ) {
2009-03-04 20:48:42 +00:00
* cos = fval ;
2007-04-30 16:16:26 +00:00
return 0 ;
}
}
2009-03-04 20:48:42 +00:00
2007-04-30 16:16:26 +00:00
return - 1 ;
}
2006-03-28 03:28:52 +00:00
int ast_str2tos ( const char * value , unsigned int * tos )
2005-08-09 16:41:28 +00:00
{
int fval ;
2006-03-28 03:28:52 +00:00
unsigned int x ;
2009-08-10 19:20:57 +00:00
if ( sscanf ( value , " %30i " , & fval ) = = 1 ) {
2006-03-28 03:28:52 +00:00
* tos = fval & 0xFF ;
return 0 ;
}
2008-07-08 16:40:28 +00:00
for ( x = 0 ; x < ARRAY_LEN ( dscp_pool1 ) ; x + + ) {
2006-03-28 03:28:52 +00:00
if ( ! strcasecmp ( value , dscp_pool1 [ x ] . name ) ) {
* tos = dscp_pool1 [ x ] . space < < 2 ;
return 0 ;
}
}
2006-09-21 22:23:49 +00:00
return - 1 ;
2005-08-09 16:41:28 +00:00
}
2006-03-28 03:28:52 +00:00
const char * ast_tos2str ( unsigned int tos )
{
unsigned int x ;
2008-07-08 16:40:28 +00:00
for ( x = 0 ; x < ARRAY_LEN ( dscp_pool1 ) ; x + + ) {
2009-03-04 20:48:42 +00:00
if ( dscp_pool1 [ x ] . space = = ( tos > > 2 ) ) {
2006-09-21 22:23:49 +00:00
return dscp_pool1 [ x ] . name ;
2009-03-04 20:48:42 +00:00
}
2006-03-28 03:28:52 +00:00
}
return " unknown " ;
}
2010-07-08 22:08:07 +00:00
int ast_get_ip ( struct ast_sockaddr * addr , const char * value )
2004-12-03 23:34:45 +00:00
{
2010-07-08 22:08:07 +00:00
return ast_get_ip_or_srv ( addr , value , NULL ) ;
2004-12-03 23:34:45 +00:00
}
2010-07-08 22:08:07 +00:00
int ast_ouraddrfor ( const struct ast_sockaddr * them , struct ast_sockaddr * us )
2003-05-04 05:52:52 +00:00
{
2010-07-08 22:08:07 +00:00
int port ;
2004-12-18 21:54:58 +00:00
int s ;
2007-11-19 08:41:14 +00:00
2010-07-08 22:08:07 +00:00
port = ast_sockaddr_port ( us ) ;
if ( ( s = socket ( ast_sockaddr_is_ipv6 ( them ) ? AF_INET6 : AF_INET ,
SOCK_DGRAM , 0 ) ) < 0 ) {
2007-11-19 08:41:14 +00:00
ast_log ( LOG_ERROR , " Cannot create socket \n " ) ;
2003-10-22 03:10:34 +00:00
return - 1 ;
}
2010-07-08 22:08:07 +00:00
if ( ast_connect ( s , them ) ) {
2004-12-18 21:54:58 +00:00
ast_log ( LOG_WARNING , " Cannot connect \n " ) ;
2004-12-28 07:44:13 +00:00
close ( s ) ;
2003-10-22 03:10:34 +00:00
return - 1 ;
}
2010-07-08 22:08:07 +00:00
if ( ast_getsockname ( s , us ) ) {
2004-12-18 21:54:58 +00:00
ast_log ( LOG_WARNING , " Cannot get socket name \n " ) ;
2004-12-28 07:44:13 +00:00
close ( s ) ;
2003-10-22 03:10:34 +00:00
return - 1 ;
}
2003-10-22 04:09:28 +00:00
close ( s ) ;
2010-07-08 22:08:07 +00:00
ast_debug ( 3 , " For destination '%s', our source address is '%s'. \n " ,
2010-07-14 22:32:29 +00:00
ast_strdupa ( ast_sockaddr_stringify_addr ( them ) ) ,
ast_strdupa ( ast_sockaddr_stringify_addr ( us ) ) ) ;
2010-07-08 22:08:07 +00:00
ast_sockaddr_set_port ( us , port ) ;
2003-05-04 05:52:52 +00:00
return 0 ;
}
2005-01-11 17:08:52 +00:00
2010-07-08 22:08:07 +00:00
int ast_find_ourip ( struct ast_sockaddr * ourip , const struct ast_sockaddr * bindaddr )
2005-02-09 03:22:42 +00:00
{
2005-07-19 23:35:45 +00:00
char ourhost [ MAXHOSTNAMELEN ] = " " ;
2010-07-08 22:08:07 +00:00
struct ast_sockaddr root ;
2005-02-09 03:22:42 +00:00
/* just use the bind address if it is nonzero */
2010-07-08 22:08:07 +00:00
if ( ! ast_sockaddr_is_any ( bindaddr ) ) {
ast_sockaddr_copy ( ourip , bindaddr ) ;
2007-11-19 08:41:14 +00:00
ast_debug ( 3 , " Attached to given IP address \n " ) ;
2005-02-09 03:22:42 +00:00
return 0 ;
}
/* try to use our hostname */
2005-07-19 23:35:45 +00:00
if ( gethostname ( ourhost , sizeof ( ourhost ) - 1 ) ) {
2005-02-09 03:22:42 +00:00
ast_log ( LOG_WARNING , " Unable to get hostname \n " ) ;
} else {
2010-07-08 22:08:07 +00:00
if ( resolve_first ( ourip , ourhost , PARSE_PORT_FORBID , 0 ) = = 0 ) {
2005-02-09 03:22:42 +00:00
return 0 ;
}
}
2007-11-19 08:41:14 +00:00
ast_debug ( 3 , " Trying to check A.ROOT-SERVERS.NET and get our IP address for that connection \n " ) ;
2005-02-09 03:22:42 +00:00
/* A.ROOT-SERVERS.NET. */
2010-07-08 22:08:07 +00:00
if ( ! resolve_first ( & root , " A.ROOT-SERVERS.NET " , PARSE_PORT_FORBID , 0 ) & &
! ast_ouraddrfor ( & root , ourip ) ) {
2005-02-09 03:22:42 +00:00
return 0 ;
2009-03-04 20:48:42 +00:00
}
2008-01-22 17:15:08 +00:00
return get_local_address ( ourip ) ;
2005-02-09 03:22:42 +00:00
}
2006-07-10 19:05:48 +00:00