2002-05-30 01:40:29 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Various sorts of access control
*
* Copyright ( C ) 1999 , Mark Spencer
*
* Mark Spencer < markster @ linux - support . net >
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/time.h>
# include <signal.h>
# include <errno.h>
# include <unistd.h>
# include <asterisk/acl.h>
# include <asterisk/logger.h>
2003-10-22 03:10:34 +00:00
# include <asterisk/channel.h>
2005-01-11 17:08:52 +00:00
# include <asterisk/options.h>
2004-05-09 08:22:15 +00:00
# include <asterisk/utils.h>
2004-06-22 18:49:00 +00:00
# include <asterisk/lock.h>
2004-12-03 23:34:45 +00:00
# include <asterisk/srv.h>
2002-05-30 01:40:29 +00:00
# include <arpa/inet.h>
# include <sys/socket.h>
# include <netdb.h>
2003-05-04 05:52:52 +00:00
# include <net/if.h>
# include <netinet/in_systm.h>
# include <netinet/ip.h>
# include <sys/ioctl.h>
2004-02-02 06:39:23 +00:00
# if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
2003-10-22 04:09:28 +00:00
# include <fcntl.h>
2003-10-22 03:10:34 +00:00
# include <net/route.h>
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( routeseq_lock ) ;
2003-10-22 03:10:34 +00:00
# endif
2002-05-30 01:40:29 +00:00
2004-12-14 23:36:30 +00:00
# if defined (SOLARIS)
# include <sys/sockio.h>
# endif
2005-01-11 17:08:52 +00:00
struct ast_netsock {
ASTOBJ_COMPONENTS ( struct ast_netsock ) ;
struct sockaddr_in bindaddr ;
int sockfd ;
int * ioref ;
struct io_context * ioc ;
} ;
2004-12-14 23:36:30 +00:00
2002-05-30 01:40:29 +00:00
struct ast_ha {
/* Host access rule */
struct in_addr netaddr ;
struct in_addr netmask ;
int sense ;
struct ast_ha * next ;
} ;
2003-05-04 05:52:52 +00:00
/* Default IP - if not otherwise set, don't breathe garbage */
2003-05-08 14:53:15 +00:00
static struct in_addr __ourip = { 0x00000000 } ;
2003-05-04 05:52:52 +00:00
struct my_ifreq {
char ifrn_name [ IFNAMSIZ ] ; /* Interface name, e.g. "eth0", "ppp0", etc. */
struct sockaddr_in ifru_addr ;
} ;
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 ;
while ( ha ) {
hal = ha ;
ha = ha - > next ;
free ( hal ) ;
}
}
2004-05-27 20:53:02 +00:00
/* Copy HA structure */
static void ast_copy_ha ( struct ast_ha * from , struct ast_ha * to )
2004-06-22 20:11:15 +00:00
{
memcpy ( & to - > netaddr , & from - > netaddr , sizeof ( from - > netaddr ) ) ;
memcpy ( & to - > netmask , & from - > netmask , sizeof ( from - > netmask ) ) ;
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 )
{
struct ast_ha * new_ha = malloc ( sizeof ( struct ast_ha ) ) ;
/* Copy from original to new object */
ast_copy_ha ( original , new_ha ) ;
return ( new_ha ) ;
}
/* Create duplicate HA link list */
/* Used in chan_sip2 templates */
struct ast_ha * ast_duplicate_ha_list ( struct ast_ha * original )
{
struct ast_ha * start = original ;
struct ast_ha * ret = NULL ;
2004-05-27 21:31:25 +00:00
struct ast_ha * link , * prev = NULL ;
2004-05-27 20:53:02 +00:00
while ( start ) {
link = ast_duplicate_ha ( start ) ; /* Create copy of this object */
2004-05-27 21:31:25 +00:00
if ( prev )
prev - > next = link ; /* Link previous to this object */
2004-05-27 20:53:02 +00:00
if ( ! ret )
ret = link ; /* Save starting point */
2004-06-22 20:11:15 +00:00
start = start - > next ; /* Go to next object */
prev = link ; /* Save pointer to this object */
}
return ( ret ) ; /* Return start of list */
2004-05-27 20:53:02 +00:00
}
2002-05-30 01:40:29 +00:00
struct ast_ha * ast_append_ha ( char * sense , char * stuff , struct ast_ha * path )
{
struct ast_ha * ha = malloc ( sizeof ( struct ast_ha ) ) ;
2004-05-27 21:31:25 +00:00
char * nm = " 255.255.255.255 " ;
2004-01-10 21:19:56 +00:00
char tmp [ 256 ] = " " ;
2002-05-30 01:40:29 +00:00
struct ast_ha * prev = NULL ;
struct ast_ha * ret ;
2004-01-10 21:43:17 +00:00
int x , z ;
unsigned int y ;
2002-05-30 01:40:29 +00:00
ret = path ;
while ( path ) {
prev = path ;
path = path - > next ;
}
if ( ha ) {
2004-01-10 21:19:56 +00:00
strncpy ( tmp , stuff , sizeof ( tmp ) - 1 ) ;
nm = strchr ( tmp , ' / ' ) ;
2002-05-30 01:40:29 +00:00
if ( ! nm )
nm = " 255.255.255.255 " ;
2004-01-10 21:19:56 +00:00
else {
* nm = ' \0 ' ;
nm + + ;
}
2004-01-10 21:43:17 +00:00
if ( ! strchr ( nm , ' . ' ) ) {
if ( ( sscanf ( nm , " %i " , & x ) = = 1 ) & & ( x > = 0 ) & & ( x < = 32 ) ) {
y = 0 ;
for ( z = 0 ; z < x ; z + + ) {
y > > = 1 ;
2004-01-10 22:19:31 +00:00
y | = 0x80000000 ;
2004-01-10 21:43:17 +00:00
}
ha - > netmask . s_addr = htonl ( y ) ;
}
} else if ( ! inet_aton ( nm , & ha - > netmask ) ) {
2005-01-17 22:53:36 +00:00
ast_log ( LOG_WARNING , " %s is not a valid netmask \n " , nm ) ;
2002-05-30 01:40:29 +00:00
free ( ha ) ;
2004-01-10 21:19:56 +00:00
return path ;
2002-05-30 01:40:29 +00:00
}
2004-01-10 21:43:17 +00:00
if ( ! inet_aton ( tmp , & ha - > netaddr ) ) {
2005-01-17 22:53:36 +00:00
ast_log ( LOG_WARNING , " %s is not a valid IP \n " , tmp ) ;
2002-05-30 01:40:29 +00:00
free ( ha ) ;
2004-01-10 21:19:56 +00:00
return path ;
2002-05-30 01:40:29 +00:00
}
ha - > netaddr . s_addr & = ha - > netmask . s_addr ;
if ( ! strncasecmp ( sense , " p " , 1 ) ) {
ha - > sense = AST_SENSE_ALLOW ;
} else {
ha - > sense = AST_SENSE_DENY ;
}
ha - > next = NULL ;
if ( prev )
prev - > next = ha ;
else
ret = ha ;
}
2004-05-27 20:53:02 +00:00
ast_log ( LOG_DEBUG , " %s/%s appended to acl for peer \n " , stuff , nm ) ;
2003-05-05 06:14:25 +00:00
return ret ;
2002-05-30 01:40:29 +00:00
}
int ast_apply_ha ( struct ast_ha * ha , struct sockaddr_in * sin )
{
/* Start optimistic */
int res = AST_SENSE_ALLOW ;
while ( ha ) {
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 */
2004-06-30 16:56:51 +00:00
ast_log ( LOG_DEBUG ,
" ##### Testing %s with %s \n " ,
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin - > sin_addr ) ,
ast_inet_ntoa ( iabuf2 , sizeof ( iabuf2 ) , ha - > netaddr ) ) ;
2002-05-30 01:40:29 +00:00
/* For each rule, if this address and the netmask = the net address
apply the current rule */
if ( ( sin - > sin_addr . s_addr & ha - > netmask . s_addr ) = = ( ha - > netaddr . s_addr ) )
res = ha - > sense ;
ha = ha - > next ;
}
return res ;
}
2004-12-03 23:34:45 +00:00
int ast_get_ip_or_srv ( struct sockaddr_in * sin , const char * value , const char * service )
2002-05-30 01:40:29 +00:00
{
struct hostent * hp ;
2004-04-22 00:20:34 +00:00
struct ast_hostent ahp ;
2004-12-03 23:34:45 +00:00
char srv [ 256 ] ;
char host [ 256 ] ;
int tportno = ntohs ( sin - > sin_port ) ;
if ( service ) {
snprintf ( srv , sizeof ( srv ) , " %s.%s " , service , value ) ;
if ( ast_get_srv ( NULL , host , sizeof ( host ) , & tportno , srv ) > 0 ) {
sin - > sin_port = htons ( tportno ) ;
value = host ;
}
}
2004-04-22 00:20:34 +00:00
hp = ast_gethostbyname ( value , & ahp ) ;
2002-05-30 01:40:29 +00:00
if ( hp ) {
memcpy ( & sin - > sin_addr , hp - > h_addr , sizeof ( sin - > sin_addr ) ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lookup '%s' \n " , value ) ;
return - 1 ;
}
return 0 ;
}
2004-12-03 23:34:45 +00:00
int ast_get_ip ( struct sockaddr_in * sin , const char * value )
{
return ast_get_ip_or_srv ( sin , value , NULL ) ;
}
2003-05-04 05:52:52 +00:00
/* iface is the interface (e.g. eth0); address is the return value */
2005-01-11 17:08:52 +00:00
int ast_lookup_iface ( char * iface , struct in_addr * address )
{
2003-05-04 05:52:52 +00:00
int mysock , res = 0 ;
struct my_ifreq ifreq ;
memset ( & ifreq , 0 , sizeof ( ifreq ) ) ;
strncpy ( ifreq . ifrn_name , iface , sizeof ( ifreq . ifrn_name ) - 1 ) ;
mysock = socket ( PF_INET , SOCK_DGRAM , IPPROTO_IP ) ;
res = ioctl ( mysock , SIOCGIFADDR , & ifreq ) ;
close ( mysock ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to get IP of %s: %s \n " , iface , strerror ( errno ) ) ;
2003-05-04 06:05:45 +00:00
memcpy ( ( char * ) address , ( char * ) & __ourip , sizeof ( __ourip ) ) ;
2003-05-04 05:52:52 +00:00
return - 1 ;
} else {
2003-05-04 06:05:45 +00:00
memcpy ( ( char * ) address , ( char * ) & ifreq . ifru_addr . sin_addr , sizeof ( ifreq . ifru_addr . sin_addr ) ) ;
2003-05-04 05:52:52 +00:00
return 0 ;
}
}
int ast_ouraddrfor ( struct in_addr * them , struct in_addr * us )
{
2004-12-18 21:54:58 +00:00
int s ;
struct sockaddr_in sin ;
socklen_t slen ;
2003-10-22 03:10:34 +00:00
2004-12-18 21:54:58 +00:00
s = socket ( PF_INET , SOCK_DGRAM , 0 ) ;
if ( s = = - 1 ) {
ast_log ( LOG_WARNING , " Cannot create socket \n " ) ;
2003-10-22 03:10:34 +00:00
return - 1 ;
}
2005-01-11 17:08:52 +00:00
sin . sin_family = AF_INET ;
sin . sin_port = 5060 ;
2004-12-18 21:54:58 +00:00
sin . sin_addr = * them ;
if ( connect ( s , ( struct sockaddr * ) & sin , sizeof ( sin ) ) ) {
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 ;
}
2004-12-18 21:54:58 +00:00
slen = sizeof ( sin ) ;
if ( getsockname ( s , ( struct sockaddr * ) & sin , & slen ) ) {
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 ) ;
2004-12-18 21:54:58 +00:00
* us = sin . sin_addr ;
2003-05-04 05:52:52 +00:00
return 0 ;
}
2005-01-11 17:08:52 +00:00
int ast_netsock_sockfd ( struct ast_netsock * ns )
{
if ( ns )
return ns - > sockfd ;
return - 1 ;
}
struct ast_netsock * ast_netsock_bindaddr ( struct ast_netsock_list * list , struct io_context * ioc , struct sockaddr_in * bindaddr , int tos , ast_io_cb callback , void * data )
{
int netsocket = - 1 ;
int * ioref ;
char iabuf [ INET_ADDRSTRLEN ] ;
struct ast_netsock * ns ;
/* Make a UDP socket */
netsocket = socket ( AF_INET , SOCK_DGRAM , IPPROTO_IP ) ;
if ( netsocket < 0 ) {
ast_log ( LOG_ERROR , " Unable to create network socket: %s \n " , strerror ( errno ) ) ;
return NULL ;
}
if ( bind ( netsocket , ( struct sockaddr * ) bindaddr , sizeof ( struct sockaddr_in ) ) ) {
ast_log ( LOG_ERROR , " Unable to bind to %s port %d: %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , bindaddr - > sin_addr ) , ntohs ( bindaddr - > sin_port ) , strerror ( errno ) ) ;
close ( netsocket ) ;
return NULL ;
}
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Using TOS bits %d \n " , tos ) ;
if ( setsockopt ( netsocket , IPPROTO_IP , IP_TOS , & tos , sizeof ( tos ) ) )
ast_log ( LOG_WARNING , " Unable to set TOS to %d \n " , tos ) ;
/* Establish I/O callback for socket read */
ioref = ast_io_add ( ioc , netsocket , callback , AST_IO_IN , data ) ;
if ( ! ioref ) {
ast_log ( LOG_WARNING , " Out of memory! \n " ) ;
close ( netsocket ) ;
return NULL ;
}
ns = malloc ( sizeof ( struct ast_netsock ) ) ;
if ( ns ) {
ASTOBJ_INIT ( ns ) ;
ns - > ioref = ioref ;
ns - > ioc = ioc ;
ns - > sockfd = netsocket ;
memcpy ( & ns - > bindaddr , bindaddr , sizeof ( ns - > bindaddr ) ) ;
ASTOBJ_CONTAINER_LINK ( list , ns ) ;
} else {
ast_log ( LOG_WARNING , " Out of memory! \n " ) ;
ast_io_remove ( ioc , ioref ) ;
close ( netsocket ) ;
}
return ns ;
}
static void ast_netsock_destroy ( struct ast_netsock * netsock )
{
ast_io_remove ( netsock - > ioc , netsock - > ioref ) ;
close ( netsock - > sockfd ) ;
free ( netsock ) ;
}
int ast_netsock_init ( struct ast_netsock_list * list )
{
memset ( list , 0 , sizeof ( struct ast_netsock_list ) ) ;
ASTOBJ_CONTAINER_INIT ( list ) ;
return 0 ;
}
int ast_netsock_release ( struct ast_netsock_list * list )
{
ASTOBJ_CONTAINER_DESTROYALL ( list , ast_netsock_destroy ) ;
ASTOBJ_CONTAINER_DESTROY ( list ) ;
return 0 ;
}
struct ast_netsock * ast_netsock_bind ( struct ast_netsock_list * list , struct io_context * ioc , const char * bindinfo , int defaultport , int tos , ast_io_cb callback , void * data )
{
struct sockaddr_in sin ;
char * tmp ;
char * port ;
int portno ;
memset ( & sin , 0 , sizeof ( sin ) ) ;
sin . sin_family = AF_INET ;
sin . sin_port = htons ( defaultport ) ;
tmp = ast_strdupa ( bindinfo ) ;
if ( tmp ) {
port = strchr ( tmp , ' : ' ) ;
if ( port ) {
* port = ' \0 ' ;
port + + ;
if ( ( portno = atoi ( port ) ) > 0 )
sin . sin_port = htons ( portno ) ;
}
2005-01-18 13:58:33 +00:00
inet_aton ( tmp , & sin . sin_addr ) ;
2005-01-11 17:08:52 +00:00
return ast_netsock_bindaddr ( list , ioc , & sin , tos , callback , data ) ;
} else
ast_log ( LOG_WARNING , " Out of memory! \n " ) ;
return NULL ;
}