2007-10-02 23:50:53 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-11-09 19:40:38 +03:00
Samba utility functions
Copyright ( C ) Andrew Tridgell 1992 - 1998
2002-01-13 14:13:54 +03:00
Copyright ( C ) Tim Potter 2000 - 2001
2007-10-04 00:43:55 +04:00
Copyright ( C ) Jeremy Allison 1992 - 2007
2007-10-02 23:50:53 +04:00
1998-11-09 19:40:38 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-11-09 19:40:38 +03:00
( at your option ) any later version .
2007-10-02 23:50:53 +04:00
1998-11-09 19:40:38 +03:00
This program 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 .
2007-10-02 23:50:53 +04:00
1998-11-09 19:40:38 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-11-09 19:40:38 +03:00
*/
# include "includes.h"
2007-10-04 00:43:55 +04:00
/****************************************************************************
2007-10-16 03:11:48 +04:00
Return true if a string could be an IPv4 address .
2007-10-04 00:43:55 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-11 05:25:16 +04:00
bool is_ipaddress_v4 ( const char * str )
2007-10-04 00:43:55 +04:00
{
2007-10-16 03:11:48 +04:00
int ret = - 1 ;
struct in_addr dest ;
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
ret = inet_pton ( AF_INET , str , & dest ) ;
if ( ret > 0 ) {
return true ;
2007-10-11 05:25:16 +04:00
}
2007-10-16 03:11:48 +04:00
return false ;
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/****************************************************************************
Return true if a string could be an IPv4 or IPv6 address .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_ipaddress ( const char * str )
{
2008-07-04 09:53:42 +04:00
# if defined(HAVE_IPV6)
2007-10-16 03:11:48 +04:00
int ret = - 1 ;
2007-10-27 03:03:20 +04:00
if ( strchr_m ( str , ' : ' ) ) {
char addr [ INET6_ADDRSTRLEN ] ;
struct in6_addr dest6 ;
const char * sp = str ;
char * p = strchr_m ( str , ' % ' ) ;
/*
* Cope with link - local .
* This is IP : v6 : addr % ifname .
*/
if ( p & & ( p > str ) & & ( if_nametoindex ( p + 1 ) ! = 0 ) ) {
strlcpy ( addr , str ,
MIN ( PTR_DIFF ( p , str ) + 1 ,
sizeof ( addr ) ) ) ;
sp = addr ;
}
2008-03-16 22:23:44 +03:00
ret = inet_pton ( AF_INET6 , sp , & dest6 ) ;
2007-10-27 03:03:20 +04:00
if ( ret > 0 ) {
return true ;
}
2007-10-16 03:11:48 +04:00
}
# endif
return is_ipaddress_v4 ( str ) ;
}
2007-10-25 01:16:54 +04:00
/****************************************************************************
2007-10-26 05:28:36 +04:00
Is a sockaddr_storage a broadcast address ?
2007-10-25 01:16:54 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_broadcast_addr ( const struct sockaddr_storage * pss )
{
# if defined(HAVE_IPV6)
if ( pss - > ss_family = = AF_INET6 ) {
const struct in6_addr * sin6 =
& ( ( const struct sockaddr_in6 * ) pss ) - > sin6_addr ;
return IN6_IS_ADDR_MULTICAST ( sin6 ) ;
}
# endif
if ( pss - > ss_family = = AF_INET ) {
uint32_t addr =
ntohl ( ( ( const struct sockaddr_in * ) pss ) - > sin_addr . s_addr ) ;
return addr = = INADDR_BROADCAST ;
}
return false ;
}
2007-10-16 03:11:48 +04:00
/*******************************************************************
Wrap getaddrinfo . . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool interpret_string_addr_internal ( struct addrinfo * * ppres ,
const char * str , int flags )
{
int ret ;
struct addrinfo hints ;
memset ( & hints , ' \0 ' , sizeof ( hints ) ) ;
/* By default make sure it supports TCP. */
hints . ai_socktype = SOCK_STREAM ;
hints . ai_flags = flags ;
2008-03-24 22:48:29 +03:00
/* Linux man page on getaddinfo() says port will be
uninitialized when service string in NULL */
2007-10-16 03:11:48 +04:00
ret = getaddrinfo ( str , NULL ,
& hints ,
ppres ) ;
2008-03-24 22:48:29 +03:00
2007-10-16 03:11:48 +04:00
if ( ret ) {
2008-02-01 17:37:11 +03:00
DEBUG ( 3 , ( " interpret_string_addr_internal: getaddrinfo failed "
2007-10-16 03:11:48 +04:00
" for name %s [%s] \n " ,
str ,
gai_strerror ( ret ) ) ) ;
return false ;
}
return true ;
2007-10-11 05:25:16 +04:00
}
/****************************************************************************
Interpret an internet address or name into an IP address in 4 byte form .
2007-10-16 03:11:48 +04:00
RETURNS IN NETWORK BYTE ORDER ( big endian ) .
2007-10-11 05:25:16 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32 interpret_addr ( const char * str )
{
2007-10-16 03:11:48 +04:00
uint32 ret ;
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* If it's in the form of an IP address then
2007-10-11 05:25:16 +04:00
* get the lib to interpret it */
if ( is_ipaddress_v4 ( str ) ) {
2007-10-16 03:11:48 +04:00
struct in_addr dest ;
if ( inet_pton ( AF_INET , str , & dest ) < = 0 ) {
/* Error - this shouldn't happen ! */
DEBUG ( 0 , ( " interpret_addr: inet_pton failed "
" host %s \n " ,
str ) ) ;
return 0 ;
}
ret = dest . s_addr ; /* NETWORK BYTE ORDER ! */
2007-10-11 05:25:16 +04:00
} else {
2007-10-16 03:11:48 +04:00
/* Otherwise assume it's a network name of some sort and use
getadddrinfo . */
struct addrinfo * res = NULL ;
struct addrinfo * res_list = NULL ;
if ( ! interpret_string_addr_internal ( & res_list ,
str ,
AI_ADDRCONFIG ) ) {
DEBUG ( 3 , ( " interpret_addr: Unknown host. %s \n " , str ) ) ;
2007-10-11 05:25:16 +04:00
return 0 ;
}
2007-10-16 03:11:48 +04:00
/* Find the first IPv4 address. */
for ( res = res_list ; res ; res = res - > ai_next ) {
if ( res - > ai_family ! = AF_INET ) {
continue ;
}
if ( res - > ai_addr = = NULL ) {
continue ;
}
break ;
}
if ( res = = NULL ) {
DEBUG ( 3 , ( " interpret_addr: host address is "
2007-10-11 05:25:16 +04:00
" invalid for host %s \n " , str ) ) ;
2007-10-16 03:11:48 +04:00
if ( res_list ) {
freeaddrinfo ( res_list ) ;
}
2007-10-11 05:25:16 +04:00
return 0 ;
}
2007-10-16 03:11:48 +04:00
putip ( ( char * ) & ret ,
& ( ( struct sockaddr_in * ) res - > ai_addr ) - > sin_addr . s_addr ) ;
if ( res_list ) {
freeaddrinfo ( res_list ) ;
}
2007-10-11 05:25:16 +04:00
}
2007-10-16 03:11:48 +04:00
/* This is so bogus - all callers need fixing... JRA. */
if ( ret = = ( uint32 ) - 1 ) {
return 0 ;
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
return ret ;
2007-10-11 05:25:16 +04:00
}
/*******************************************************************
A convenient addition to interpret_addr ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-04 08:34:46 +03:00
struct in_addr * interpret_addr2 ( struct in_addr * ip , const char * str )
2007-10-11 05:25:16 +04:00
{
uint32 a = interpret_addr ( str ) ;
2007-11-04 08:34:46 +03:00
ip - > s_addr = a ;
return ip ;
2007-10-11 05:25:16 +04:00
}
/*******************************************************************
Map a text hostname or IP address ( IPv4 or IPv6 ) into a
struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-16 03:11:48 +04:00
bool interpret_string_addr ( struct sockaddr_storage * pss ,
const char * str ,
int flags )
2007-10-11 05:25:16 +04:00
{
struct addrinfo * res = NULL ;
2007-10-27 03:03:20 +04:00
# if defined(HAVE_IPV6)
2008-07-04 09:53:42 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
2007-10-27 03:03:20 +04:00
unsigned int scope_id = 0 ;
if ( strchr_m ( str , ' : ' ) ) {
char * p = strchr_m ( str , ' % ' ) ;
/*
* Cope with link - local .
* This is IP : v6 : addr % ifname .
*/
if ( p & & ( p > str ) & & ( ( scope_id = if_nametoindex ( p + 1 ) ) ! = 0 ) ) {
strlcpy ( addr , str ,
MIN ( PTR_DIFF ( p , str ) + 1 ,
sizeof ( addr ) ) ) ;
str = addr ;
}
}
# endif
2007-10-11 05:25:16 +04:00
2007-10-28 06:29:36 +03:00
zero_addr ( pss ) ;
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
if ( ! interpret_string_addr_internal ( & res , str , flags | AI_ADDRCONFIG ) ) {
return false ;
}
if ( ! res ) {
2007-10-11 05:25:16 +04:00
return false ;
}
/* Copy the first sockaddr. */
memcpy ( pss , res - > ai_addr , res - > ai_addrlen ) ;
2007-10-27 03:03:20 +04:00
# if defined(HAVE_IPV6)
if ( pss - > ss_family = = AF_INET6 & & scope_id ) {
struct sockaddr_in6 * ps6 = ( struct sockaddr_in6 * ) pss ;
if ( IN6_IS_ADDR_LINKLOCAL ( & ps6 - > sin6_addr ) & &
ps6 - > sin6_scope_id = = 0 ) {
ps6 - > sin6_scope_id = scope_id ;
}
}
# endif
2007-10-11 05:25:16 +04:00
freeaddrinfo ( res ) ;
return true ;
}
/*******************************************************************
Check if an IPv7 is 127.0 .0 .1
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_loopback_ip_v4 ( struct in_addr ip )
{
struct in_addr a ;
a . s_addr = htonl ( INADDR_LOOPBACK ) ;
return ( ip . s_addr = = a . s_addr ) ;
}
/*******************************************************************
Check if a struct sockaddr_storage is the loopback address .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_loopback_addr ( const struct sockaddr_storage * pss )
{
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-26 06:07:25 +04:00
if ( pss - > ss_family = = AF_INET6 ) {
2007-10-16 03:11:48 +04:00
struct in6_addr * pin6 =
& ( ( struct sockaddr_in6 * ) pss ) - > sin6_addr ;
2007-10-11 05:25:16 +04:00
return IN6_IS_ADDR_LOOPBACK ( pin6 ) ;
}
# endif
if ( pss - > ss_family = = AF_INET ) {
struct in_addr * pin = & ( ( struct sockaddr_in * ) pss ) - > sin_addr ;
return is_loopback_ip_v4 ( * pin ) ;
}
return false ;
}
/*******************************************************************
Check if an IPv4 is 0.0 .0 .0 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_zero_ip_v4 ( struct in_addr ip )
{
uint32 a ;
putip ( ( char * ) & a , ( char * ) & ip ) ;
return ( a = = 0 ) ;
}
/*******************************************************************
Check if a struct sockaddr_storage has an unspecified address .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_zero_addr ( const struct sockaddr_storage * pss )
{
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-26 06:07:25 +04:00
if ( pss - > ss_family = = AF_INET6 ) {
2007-10-16 03:11:48 +04:00
struct in6_addr * pin6 =
& ( ( struct sockaddr_in6 * ) pss ) - > sin6_addr ;
2007-10-11 05:25:16 +04:00
return IN6_IS_ADDR_UNSPECIFIED ( pin6 ) ;
}
# endif
if ( pss - > ss_family = = AF_INET ) {
struct in_addr * pin = & ( ( struct sockaddr_in * ) pss ) - > sin_addr ;
return is_zero_ip_v4 ( * pin ) ;
2007-10-04 00:43:55 +04:00
}
2007-10-11 05:25:16 +04:00
return false ;
}
/*******************************************************************
Set an IP to 0.0 .0 .0 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void zero_ip_v4 ( struct in_addr * ip )
{
2007-11-04 08:34:46 +03:00
memset ( ip , ' \0 ' , sizeof ( struct in_addr ) ) ;
2007-10-11 05:25:16 +04:00
}
2007-10-25 01:16:54 +04:00
/*******************************************************************
2007-10-28 06:29:36 +03:00
Set an address to INADDR_ANY .
2007-10-25 01:16:54 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-28 06:29:36 +03:00
void zero_addr ( struct sockaddr_storage * pss )
2007-10-25 01:16:54 +04:00
{
memset ( pss , ' \0 ' , sizeof ( * pss ) ) ;
/* Ensure we're at least a valid sockaddr-storage. */
2007-10-28 06:29:36 +03:00
pss - > ss_family = AF_INET ;
2007-10-25 01:16:54 +04:00
}
2007-10-11 05:25:16 +04:00
/*******************************************************************
Are two IPs on the same subnet - IPv4 version ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool same_net_v4 ( struct in_addr ip1 , struct in_addr ip2 , struct in_addr mask )
{
uint32 net1 , net2 , nmask ;
nmask = ntohl ( mask . s_addr ) ;
net1 = ntohl ( ip1 . s_addr ) ;
net2 = ntohl ( ip2 . s_addr ) ;
return ( ( net1 & nmask ) = = ( net2 & nmask ) ) ;
}
/*******************************************************************
Convert an IPv4 struct in_addr to a struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void in_addr_to_sockaddr_storage ( struct sockaddr_storage * ss ,
struct in_addr ip )
{
struct sockaddr_in * sa = ( struct sockaddr_in * ) ss ;
memset ( ss , ' \0 ' , sizeof ( * ss ) ) ;
2008-07-08 06:30:47 +04:00
sa - > sin_family = AF_INET ;
2007-10-11 05:25:16 +04:00
sa - > sin_addr = ip ;
}
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-11 05:25:16 +04:00
/*******************************************************************
Convert an IPv6 struct in_addr to a struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-02-29 15:35:16 +03:00
void in6_addr_to_sockaddr_storage ( struct sockaddr_storage * ss ,
2007-10-11 05:25:16 +04:00
struct in6_addr ip )
{
struct sockaddr_in6 * sa = ( struct sockaddr_in6 * ) ss ;
memset ( ss , ' \0 ' , sizeof ( * ss ) ) ;
2008-07-08 06:30:47 +04:00
sa - > sin6_family = AF_INET6 ;
2007-10-11 05:25:16 +04:00
sa - > sin6_addr = ip ;
}
# endif
/*******************************************************************
Are two IPs on the same subnet ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool same_net ( const struct sockaddr_storage * ip1 ,
const struct sockaddr_storage * ip2 ,
const struct sockaddr_storage * mask )
{
if ( ip1 - > ss_family ! = ip2 - > ss_family ) {
/* Never on the same net. */
return false ;
}
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-11 05:25:16 +04:00
if ( ip1 - > ss_family = = AF_INET6 ) {
struct sockaddr_in6 ip1_6 = * ( struct sockaddr_in6 * ) ip1 ;
struct sockaddr_in6 ip2_6 = * ( struct sockaddr_in6 * ) ip2 ;
struct sockaddr_in6 mask_6 = * ( struct sockaddr_in6 * ) mask ;
char * p1 = ( char * ) & ip1_6 . sin6_addr ;
char * p2 = ( char * ) & ip2_6 . sin6_addr ;
char * m = ( char * ) & mask_6 . sin6_addr ;
int i ;
for ( i = 0 ; i < sizeof ( struct in6_addr ) ; i + + ) {
* p1 + + & = * m ;
* p2 + + & = * m ;
m + + ;
}
return ( memcmp ( & ip1_6 . sin6_addr ,
& ip2_6 . sin6_addr ,
sizeof ( struct in6_addr ) ) = = 0 ) ;
}
# endif
if ( ip1 - > ss_family = = AF_INET ) {
return same_net_v4 ( ( ( const struct sockaddr_in * ) ip1 ) - > sin_addr ,
( ( const struct sockaddr_in * ) ip2 ) - > sin_addr ,
( ( const struct sockaddr_in * ) mask ) - > sin_addr ) ;
}
return false ;
}
/*******************************************************************
Are two sockaddr_storage ' s the same family and address ? Ignore port etc .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool addr_equal ( const struct sockaddr_storage * ip1 ,
const struct sockaddr_storage * ip2 )
{
if ( ip1 - > ss_family ! = ip2 - > ss_family ) {
/* Never the same. */
return false ;
}
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-11 05:25:16 +04:00
if ( ip1 - > ss_family = = AF_INET6 ) {
return ( memcmp ( & ( ( const struct sockaddr_in6 * ) ip1 ) - > sin6_addr ,
& ( ( const struct sockaddr_in6 * ) ip2 ) - > sin6_addr ,
sizeof ( struct in6_addr ) ) = = 0 ) ;
}
# endif
if ( ip1 - > ss_family = = AF_INET ) {
return ( memcmp ( & ( ( const struct sockaddr_in * ) ip1 ) - > sin_addr ,
& ( ( const struct sockaddr_in * ) ip2 ) - > sin_addr ,
sizeof ( struct in_addr ) ) = = 0 ) ;
}
return false ;
}
/****************************************************************************
Is an IP address the INADDR_ANY or in6addr_any value ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_address_any ( const struct sockaddr_storage * psa )
{
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-04 00:43:55 +04:00
if ( psa - > ss_family = = AF_INET6 ) {
2007-10-11 05:25:16 +04:00
struct sockaddr_in6 * si6 = ( struct sockaddr_in6 * ) psa ;
if ( memcmp ( & in6addr_any ,
& si6 - > sin6_addr ,
sizeof ( in6addr_any ) ) = = 0 ) {
return true ;
}
return false ;
2007-10-04 00:43:55 +04:00
}
# endif
if ( psa - > ss_family = = AF_INET ) {
2007-10-11 05:25:16 +04:00
struct sockaddr_in * si = ( struct sockaddr_in * ) psa ;
if ( si - > sin_addr . s_addr = = INADDR_ANY ) {
return true ;
}
return false ;
2007-10-04 00:43:55 +04:00
}
2007-10-11 05:25:16 +04:00
return false ;
}
2008-01-17 00:21:46 +03:00
/****************************************************************************
Get a port number in host byte order from a sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint16_t get_sockaddr_port ( const struct sockaddr_storage * pss )
{
uint16_t port = 0 ;
if ( pss - > ss_family ! = AF_INET ) {
# if defined(HAVE_IPV6)
/* IPv6 */
const struct sockaddr_in6 * sa6 =
( const struct sockaddr_in6 * ) pss ;
port = ntohs ( sa6 - > sin6_port ) ;
# endif
} else {
const struct sockaddr_in * sa =
( const struct sockaddr_in * ) pss ;
port = ntohs ( sa - > sin_port ) ;
}
return port ;
}
2007-10-11 05:25:16 +04:00
/****************************************************************************
Print out an IPv4 or IPv6 address from a struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-02 20:25:34 +03:00
static char * print_sockaddr_len ( char * dest ,
2007-10-11 05:25:16 +04:00
size_t destlen ,
const struct sockaddr_storage * psa ,
socklen_t psalen )
{
if ( destlen > 0 ) {
dest [ 0 ] = ' \0 ' ;
}
2007-11-02 20:25:34 +03:00
( void ) sys_getnameinfo ( ( const struct sockaddr * ) psa ,
2007-10-11 05:25:16 +04:00
psalen ,
dest , destlen ,
NULL , 0 ,
NI_NUMERICHOST ) ;
2007-10-04 00:43:55 +04:00
return dest ;
}
1998-11-09 19:40:38 +03:00
2007-10-25 01:16:54 +04:00
/****************************************************************************
Print out an IPv4 or IPv6 address from a struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * print_sockaddr ( char * dest ,
size_t destlen ,
const struct sockaddr_storage * psa )
{
2007-11-02 20:25:34 +03:00
return print_sockaddr_len ( dest , destlen , psa ,
sizeof ( struct sockaddr_storage ) ) ;
2007-10-25 01:16:54 +04:00
}
/****************************************************************************
Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * print_canonical_sockaddr ( TALLOC_CTX * ctx ,
const struct sockaddr_storage * pss )
{
char addr [ INET6_ADDRSTRLEN ] ;
char * dest = NULL ;
int ret ;
2008-03-24 22:48:29 +03:00
/* Linux getnameinfo() man pages says port is unitialized if
service name is NULL . */
2008-01-17 00:21:46 +03:00
ret = sys_getnameinfo ( ( const struct sockaddr * ) pss ,
2007-10-25 01:16:54 +04:00
sizeof ( struct sockaddr_storage ) ,
addr , sizeof ( addr ) ,
NULL , 0 ,
NI_NUMERICHOST ) ;
2008-03-24 22:48:29 +03:00
if ( ret ! = 0 ) {
2007-10-25 01:16:54 +04:00
return NULL ;
}
2008-03-27 00:58:27 +03:00
if ( pss - > ss_family ! = AF_INET ) {
2007-10-25 01:16:54 +04:00
# if defined(HAVE_IPV6)
2008-03-27 00:58:27 +03:00
dest = talloc_asprintf ( ctx , " [%s] " , addr ) ;
2007-10-25 01:16:54 +04:00
# else
2008-03-27 00:58:27 +03:00
return NULL ;
2007-10-25 01:16:54 +04:00
# endif
2008-03-27 00:58:27 +03:00
} else {
dest = talloc_asprintf ( ctx , " %s " , addr ) ;
}
2007-10-25 01:16:54 +04:00
return dest ;
}
2007-10-11 05:25:16 +04:00
/****************************************************************************
2007-11-04 08:34:46 +03:00
Return the string of an IP address ( IPv4 or IPv6 ) .
2007-10-11 05:25:16 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-04 08:34:46 +03:00
static const char * get_socket_addr ( int fd , char * addr_buf , size_t addr_len )
2004-02-10 07:02:53 +03:00
{
2007-10-04 00:43:55 +04:00
struct sockaddr_storage sa ;
2004-05-05 07:03:38 +04:00
socklen_t length = sizeof ( sa ) ;
2004-02-10 07:02:53 +03:00
2007-10-08 06:48:03 +04:00
/* Ok, returning a hard coded IPv4 address
* is bogus , but it ' s just as bogus as a
* zero IPv6 address . No good choice here .
*/
2007-11-07 23:48:58 +03:00
strlcpy ( addr_buf , " 0.0.0.0 " , addr_len ) ;
2004-02-10 07:02:53 +03:00
if ( fd = = - 1 ) {
return addr_buf ;
}
2007-10-02 23:50:53 +04:00
2007-10-04 00:43:55 +04:00
if ( getsockname ( fd , ( struct sockaddr * ) & sa , & length ) < 0 ) {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " getsockname failed. Error was %s \n " ,
2007-10-04 00:43:55 +04:00
strerror ( errno ) ) ) ;
2004-02-10 07:02:53 +03:00
return addr_buf ;
}
2007-10-02 23:50:53 +04:00
2007-11-04 08:34:46 +03:00
return print_sockaddr_len ( addr_buf , addr_len , & sa , length ) ;
2004-02-10 07:02:53 +03:00
}
2007-11-04 09:20:10 +03:00
#if 0
/* Not currently used. JRA. */
2007-10-11 05:25:16 +04:00
/****************************************************************************
Return the port number we ' ve bound to on a socket .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-06-10 21:09:00 +04:00
static int get_socket_port ( int fd )
{
2007-10-04 00:43:55 +04:00
struct sockaddr_storage sa ;
2004-06-10 21:09:00 +04:00
socklen_t length = sizeof ( sa ) ;
2007-10-04 00:43:55 +04:00
if ( fd = = - 1 ) {
2004-06-10 21:09:00 +04:00
return - 1 ;
2007-10-04 00:43:55 +04:00
}
2007-10-02 23:50:53 +04:00
2007-10-04 00:43:55 +04:00
if ( getsockname ( fd , ( struct sockaddr * ) & sa , & length ) < 0 ) {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " getpeername failed. Error was %s \n " ,
2007-10-04 00:43:55 +04:00
strerror ( errno ) ) ) ;
2004-06-10 21:09:00 +04:00
return - 1 ;
}
2007-10-02 23:50:53 +04:00
2007-10-19 17:14:12 +04:00
# if defined(HAVE_IPV6)
2007-10-04 00:43:55 +04:00
if ( sa . ss_family = = AF_INET6 ) {
return ntohs ( ( ( struct sockaddr_in6 * ) & sa ) - > sin6_port ) ;
}
# endif
if ( sa . ss_family = = AF_INET ) {
return ntohs ( ( ( struct sockaddr_in * ) & sa ) - > sin_port ) ;
}
return - 1 ;
2004-06-10 21:09:00 +04:00
}
2007-11-04 09:20:10 +03:00
# endif
2004-06-10 21:09:00 +04:00
2007-11-21 21:10:52 +03:00
void set_sockaddr_port ( struct sockaddr_storage * psa , uint16 port )
{
# if defined(HAVE_IPV6)
if ( psa - > ss_family = = AF_INET6 ) {
( ( struct sockaddr_in6 * ) psa ) - > sin6_port = htons ( port ) ;
}
2007-11-21 21:31:18 +03:00
# endif
2007-11-21 21:10:52 +03:00
if ( psa - > ss_family = = AF_INET ) {
( ( struct sockaddr_in * ) psa ) - > sin_port = htons ( port ) ;
}
}
2007-11-04 09:20:10 +03:00
const char * client_name ( int fd )
2005-06-14 02:26:08 +04:00
{
2007-11-04 09:20:10 +03:00
return get_peer_name ( fd , false ) ;
2005-06-14 02:26:08 +04:00
}
2007-11-04 09:20:10 +03:00
const char * client_addr ( int fd , char * addr , size_t addrlen )
2005-06-14 02:26:08 +04:00
{
2007-11-04 09:20:10 +03:00
return get_peer_addr ( fd , addr , addrlen ) ;
2005-06-14 02:26:08 +04:00
}
2007-11-04 09:20:10 +03:00
const char * client_socket_addr ( int fd , char * addr , size_t addr_len )
2005-06-14 02:26:08 +04:00
{
2007-11-04 09:20:10 +03:00
return get_socket_addr ( fd , addr , addr_len ) ;
2005-06-14 02:26:08 +04:00
}
2007-11-04 09:20:10 +03:00
#if 0
/* Not currently used. JRA. */
int client_socket_port ( int fd )
2005-06-14 02:26:08 +04:00
{
2007-11-04 09:20:10 +03:00
return get_socket_port ( fd ) ;
2005-06-14 02:26:08 +04:00
}
2007-11-04 09:20:10 +03:00
# endif
2005-06-14 02:26:08 +04:00
2007-11-04 01:12:42 +03:00
/****************************************************************************
Accessor functions to make thread - safe code easier later . . .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-05 22:12:56 +03:00
void set_smb_read_error ( enum smb_read_errors * pre ,
enum smb_read_errors newerr )
2007-11-04 01:12:42 +03:00
{
2007-11-05 22:12:56 +03:00
if ( pre ) {
* pre = newerr ;
}
2007-11-04 01:12:42 +03:00
}
2007-11-05 22:12:56 +03:00
void cond_set_smb_read_error ( enum smb_read_errors * pre ,
enum smb_read_errors newerr )
2007-11-04 01:12:42 +03:00
{
2007-11-05 22:12:56 +03:00
if ( pre & & * pre = = SMB_READ_OK ) {
* pre = newerr ;
2007-11-04 01:12:42 +03:00
}
}
2005-06-14 02:26:08 +04:00
1998-11-09 19:40:38 +03:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Determine if a file descriptor is in fact a socket .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2007-10-11 05:25:16 +04:00
bool is_a_socket ( int fd )
1998-11-09 19:40:38 +03:00
{
2004-05-05 07:03:38 +04:00
int v ;
socklen_t l ;
2002-07-15 14:35:28 +04:00
l = sizeof ( int ) ;
return ( getsockopt ( fd , SOL_SOCKET , SO_TYPE , ( char * ) & v , & l ) = = 0 ) ;
1998-11-09 19:40:38 +03:00
}
enum SOCK_OPT_TYPES { OPT_BOOL , OPT_INT , OPT_ON } ;
2002-07-15 14:35:28 +04:00
typedef struct smb_socket_option {
2003-01-03 11:28:12 +03:00
const char * name ;
2002-07-15 14:35:28 +04:00
int level ;
int option ;
int value ;
int opttype ;
2000-10-07 01:12:25 +04:00
} smb_socket_option ;
2002-07-15 14:35:28 +04:00
static const smb_socket_option socket_options [ ] = {
2007-10-02 23:50:53 +04:00
{ " SO_KEEPALIVE " , SOL_SOCKET , SO_KEEPALIVE , 0 , OPT_BOOL } ,
{ " SO_REUSEADDR " , SOL_SOCKET , SO_REUSEADDR , 0 , OPT_BOOL } ,
{ " SO_BROADCAST " , SOL_SOCKET , SO_BROADCAST , 0 , OPT_BOOL } ,
1998-11-09 19:40:38 +03:00
# ifdef TCP_NODELAY
2007-10-02 23:50:53 +04:00
{ " TCP_NODELAY " , IPPROTO_TCP , TCP_NODELAY , 0 , OPT_BOOL } ,
1998-11-09 19:40:38 +03:00
# endif
2005-05-01 14:13:08 +04:00
# ifdef TCP_KEEPCNT
2007-10-02 23:50:53 +04:00
{ " TCP_KEEPCNT " , IPPROTO_TCP , TCP_KEEPCNT , 0 , OPT_INT } ,
2005-05-01 14:13:08 +04:00
# endif
# ifdef TCP_KEEPIDLE
2007-10-02 23:50:53 +04:00
{ " TCP_KEEPIDLE " , IPPROTO_TCP , TCP_KEEPIDLE , 0 , OPT_INT } ,
2005-05-01 14:13:08 +04:00
# endif
# ifdef TCP_KEEPINTVL
2007-10-02 23:50:53 +04:00
{ " TCP_KEEPINTVL " , IPPROTO_TCP , TCP_KEEPINTVL , 0 , OPT_INT } ,
2005-05-01 14:13:08 +04:00
# endif
1998-11-09 19:40:38 +03:00
# ifdef IPTOS_LOWDELAY
2007-10-02 23:50:53 +04:00
{ " IPTOS_LOWDELAY " , IPPROTO_IP , IP_TOS , IPTOS_LOWDELAY , OPT_ON } ,
1998-11-09 19:40:38 +03:00
# endif
# ifdef IPTOS_THROUGHPUT
2007-10-02 23:50:53 +04:00
{ " IPTOS_THROUGHPUT " , IPPROTO_IP , IP_TOS , IPTOS_THROUGHPUT , OPT_ON } ,
1998-11-09 19:40:38 +03:00
# endif
2000-02-17 01:48:19 +03:00
# ifdef SO_REUSEPORT
2007-10-02 23:50:53 +04:00
{ " SO_REUSEPORT " , SOL_SOCKET , SO_REUSEPORT , 0 , OPT_BOOL } ,
2000-02-17 01:48:19 +03:00
# endif
1998-11-09 19:40:38 +03:00
# ifdef SO_SNDBUF
2007-10-02 23:50:53 +04:00
{ " SO_SNDBUF " , SOL_SOCKET , SO_SNDBUF , 0 , OPT_INT } ,
1998-11-09 19:40:38 +03:00
# endif
# ifdef SO_RCVBUF
2007-10-02 23:50:53 +04:00
{ " SO_RCVBUF " , SOL_SOCKET , SO_RCVBUF , 0 , OPT_INT } ,
1998-11-09 19:40:38 +03:00
# endif
# ifdef SO_SNDLOWAT
2007-10-02 23:50:53 +04:00
{ " SO_SNDLOWAT " , SOL_SOCKET , SO_SNDLOWAT , 0 , OPT_INT } ,
1998-11-09 19:40:38 +03:00
# endif
# ifdef SO_RCVLOWAT
2007-10-02 23:50:53 +04:00
{ " SO_RCVLOWAT " , SOL_SOCKET , SO_RCVLOWAT , 0 , OPT_INT } ,
1998-11-09 19:40:38 +03:00
# endif
# ifdef SO_SNDTIMEO
2007-10-02 23:50:53 +04:00
{ " SO_SNDTIMEO " , SOL_SOCKET , SO_SNDTIMEO , 0 , OPT_INT } ,
1998-11-09 19:40:38 +03:00
# endif
# ifdef SO_RCVTIMEO
2007-10-02 23:50:53 +04:00
{ " SO_RCVTIMEO " , SOL_SOCKET , SO_RCVTIMEO , 0 , OPT_INT } ,
2006-01-16 02:13:47 +03:00
# endif
# ifdef TCP_FASTACK
2007-10-02 23:50:53 +04:00
{ " TCP_FASTACK " , IPPROTO_TCP , TCP_FASTACK , 0 , OPT_INT } ,
1998-11-09 19:40:38 +03:00
# endif
{ NULL , 0 , 0 , 0 , 0 } } ;
2000-10-07 01:12:25 +04:00
/****************************************************************************
Print socket options .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
2000-10-07 01:12:25 +04:00
static void print_socket_options ( int s )
{
2004-05-05 07:03:38 +04:00
int value ;
socklen_t vlen = 4 ;
2002-07-15 14:35:28 +04:00
const smb_socket_option * p = & socket_options [ 0 ] ;
2000-10-07 01:12:25 +04:00
2007-10-02 23:50:53 +04:00
/* wrapped in if statement to prevent streams
* leak in SCO Openserver 5.0 */
2003-04-11 18:18:02 +04:00
/* reported on samba-technical --jerry */
if ( DEBUGLEVEL > = 5 ) {
2007-10-02 23:50:53 +04:00
for ( ; p - > name ! = NULL ; p + + ) {
if ( getsockopt ( s , p - > level , p - > option ,
( void * ) & value , & vlen ) = = - 1 ) {
DEBUG ( 5 , ( " Could not test socket option %s. \n " ,
p - > name ) ) ;
} else {
DEBUG ( 5 , ( " socket option %s = %d \n " ,
p - > name , value ) ) ;
2003-04-11 18:18:02 +04:00
}
2000-10-07 01:12:25 +04:00
}
}
}
1998-11-09 19:40:38 +03:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Set user socket options .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2002-11-13 02:20:50 +03:00
void set_socket_options ( int fd , const char * options )
1998-11-09 19:40:38 +03:00
{
2007-12-08 04:32:32 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
char * tok ;
1999-12-13 16:27:58 +03:00
2007-12-08 04:32:32 +03:00
while ( next_token_talloc ( ctx , & options , & tok , " \t , " ) ) {
1999-12-13 16:27:58 +03:00
int ret = 0 , i ;
int value = 1 ;
char * p ;
2007-10-11 05:25:16 +04:00
bool got_value = false ;
1999-12-13 16:27:58 +03:00
2001-07-04 11:36:09 +04:00
if ( ( p = strchr_m ( tok , ' = ' ) ) ) {
1999-12-13 16:27:58 +03:00
* p = 0 ;
value = atoi ( p + 1 ) ;
2007-10-11 05:25:16 +04:00
got_value = true ;
1999-12-13 16:27:58 +03:00
}
1998-11-09 19:40:38 +03:00
1999-12-13 16:27:58 +03:00
for ( i = 0 ; socket_options [ i ] . name ; i + + )
if ( strequal ( socket_options [ i ] . name , tok ) )
break ;
1998-11-09 19:40:38 +03:00
1999-12-13 16:27:58 +03:00
if ( ! socket_options [ i ] . name ) {
DEBUG ( 0 , ( " Unknown socket option %s \n " , tok ) ) ;
continue ;
}
1998-11-09 19:40:38 +03:00
1999-12-13 16:27:58 +03:00
switch ( socket_options [ i ] . opttype ) {
case OPT_BOOL :
case OPT_INT :
ret = setsockopt ( fd , socket_options [ i ] . level ,
2007-10-02 23:50:53 +04:00
socket_options [ i ] . option ,
( char * ) & value , sizeof ( int ) ) ;
1999-12-13 16:27:58 +03:00
break ;
case OPT_ON :
if ( got_value )
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " syntax error - %s "
" does not take a value \n " , tok ) ) ;
1999-12-13 16:27:58 +03:00
{
int on = socket_options [ i ] . value ;
ret = setsockopt ( fd , socket_options [ i ] . level ,
2007-10-02 23:50:53 +04:00
socket_options [ i ] . option ,
( char * ) & on , sizeof ( int ) ) ;
1999-12-13 16:27:58 +03:00
}
2007-10-02 23:50:53 +04:00
break ;
}
if ( ret ! = 0 ) {
2008-04-07 13:22:14 +04:00
/* be aware that some systems like Solaris return
* EINVAL to a setsockopt ( ) call when the client
* sent a RST previously - no need to worry */
DEBUG ( 2 , ( " Failed to set socket option %s (Error %s) \n " ,
2007-10-02 23:50:53 +04:00
tok , strerror ( errno ) ) ) ;
1999-12-13 16:27:58 +03:00
}
}
2000-10-07 01:12:25 +04:00
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( ctx ) ;
2000-10-07 01:12:25 +04:00
print_socket_options ( fd ) ;
1998-11-09 19:40:38 +03:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Read from a socket .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-04 00:43:55 +04:00
ssize_t read_udp_v4_socket ( int fd ,
char * buf ,
size_t len ,
struct sockaddr_storage * psa )
1998-11-09 19:40:38 +03:00
{
2001-06-27 21:26:29 +04:00
ssize_t ret ;
2007-10-04 00:43:55 +04:00
socklen_t socklen = sizeof ( * psa ) ;
struct sockaddr_in * si = ( struct sockaddr_in * ) psa ;
memset ( ( char * ) psa , ' \0 ' , socklen ) ;
2001-06-27 21:26:29 +04:00
2007-10-02 23:50:53 +04:00
ret = ( ssize_t ) sys_recvfrom ( fd , buf , len , 0 ,
2007-10-04 00:43:55 +04:00
( struct sockaddr * ) psa , & socklen ) ;
2001-06-27 21:26:29 +04:00
if ( ret < = 0 ) {
2006-05-18 23:49:44 +04:00
/* Don't print a low debug error for a non-blocking socket. */
if ( errno = = EAGAIN ) {
2007-10-04 00:43:55 +04:00
DEBUG ( 10 , ( " read_udp_v4_socket: returned EAGAIN \n " ) ) ;
2006-05-18 23:49:44 +04:00
} else {
2007-10-04 00:43:55 +04:00
DEBUG ( 2 , ( " read_udp_v4_socket: failed. errno=%s \n " ,
strerror ( errno ) ) ) ;
2006-05-18 23:49:44 +04:00
}
2007-10-04 00:43:55 +04:00
return 0 ;
2001-06-27 21:26:29 +04:00
}
2007-10-04 00:43:55 +04:00
if ( psa - > ss_family ! = AF_INET ) {
2007-10-05 05:11:33 +04:00
DEBUG ( 2 , ( " read_udp_v4_socket: invalid address family %d "
2007-10-04 00:43:55 +04:00
" (not IPv4) \n " , ( int ) psa - > ss_family ) ) ;
return 0 ;
}
2001-06-27 21:26:29 +04:00
2007-10-05 05:11:33 +04:00
DEBUG ( 10 , ( " read_udp_v4_socket: ip %s port %d read: %lu \n " ,
2007-10-04 00:43:55 +04:00
inet_ntoa ( si - > sin_addr ) ,
si - > sin_port ,
( unsigned long ) ret ) ) ;
2001-06-27 21:26:29 +04:00
2007-10-04 00:43:55 +04:00
return ret ;
1998-11-09 19:40:38 +03:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Read data from a socket with a timout in msec .
mincount = if timeout , minimum to read before returning
maxcount = number to be read .
time_out = timeout in milliseconds
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-01-26 01:43:50 +03:00
NTSTATUS read_socket_with_timeout ( int fd , char * buf ,
size_t mincnt , size_t maxcnt ,
unsigned int time_out ,
size_t * size_ret )
1998-11-09 19:40:38 +03:00
{
2002-01-13 15:33:42 +03:00
fd_set fds ;
int selrtn ;
ssize_t readret ;
size_t nread = 0 ;
struct timeval timeout ;
2007-11-04 09:20:10 +03:00
char addr [ INET6_ADDRSTRLEN ] ;
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
/* just checking .... */
if ( maxcnt < = 0 )
2008-01-24 21:17:14 +03:00
return NT_STATUS_OK ;
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
/* Blocking read */
2005-06-14 02:26:08 +04:00
if ( time_out = = 0 ) {
if ( mincnt = = 0 ) {
mincnt = maxcnt ;
}
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
while ( nread < mincnt ) {
2002-07-15 14:35:28 +04:00
readret = sys_read ( fd , buf + nread , maxcnt - nread ) ;
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
if ( readret = = 0 ) {
2007-10-02 23:50:53 +04:00
DEBUG ( 5 , ( " read_socket_with_timeout: "
" blocking read. EOF from client. \n " ) ) ;
2008-01-24 21:17:14 +03:00
return NT_STATUS_END_OF_FILE ;
2002-01-13 15:33:42 +03:00
}
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
if ( readret = = - 1 ) {
2007-11-04 09:20:10 +03:00
if ( fd = = get_client_fd ( ) ) {
2007-10-02 23:50:53 +04:00
/* Try and give an error message
* saying what client failed . */
DEBUG ( 0 , ( " read_socket_with_timeout: "
" client %s read error = %s. \n " ,
2007-11-04 09:20:10 +03:00
get_peer_addr ( fd , addr , sizeof ( addr ) ) ,
2007-10-02 23:50:53 +04:00
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
} else {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " read_socket_with_timeout: "
" read error = %s. \n " ,
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
}
2008-01-24 21:17:14 +03:00
return map_nt_error_from_unix ( errno ) ;
2002-01-13 15:33:42 +03:00
}
nread + = readret ;
}
2008-01-24 21:17:14 +03:00
goto done ;
2002-01-13 15:33:42 +03:00
}
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
/* Most difficult - timeout read */
2007-10-02 23:50:53 +04:00
/* If this is ever called on a disk file and
2002-01-13 15:33:42 +03:00
mincnt is greater then the filesize then
2007-10-02 23:50:53 +04:00
system performance will suffer severely as
2002-01-13 15:33:42 +03:00
select always returns true on disk files */
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
/* Set initial timeout */
timeout . tv_sec = ( time_t ) ( time_out / 1000 ) ;
timeout . tv_usec = ( long ) ( 1000 * ( time_out % 1000 ) ) ;
2007-10-02 23:50:53 +04:00
for ( nread = 0 ; nread < mincnt ; ) {
2002-01-13 15:33:42 +03:00
FD_ZERO ( & fds ) ;
FD_SET ( fd , & fds ) ;
2007-10-02 23:50:53 +04:00
2002-02-01 02:26:12 +03:00
selrtn = sys_select_intr ( fd + 1 , & fds , NULL , NULL , & timeout ) ;
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
/* Check if error */
2002-01-13 15:37:01 +03:00
if ( selrtn = = - 1 ) {
2002-01-13 15:33:42 +03:00
/* something is wrong. Maybe the socket is dead? */
2007-11-04 09:20:10 +03:00
if ( fd = = get_client_fd ( ) ) {
2007-10-02 23:50:53 +04:00
/* Try and give an error message saying
* what client failed . */
DEBUG ( 0 , ( " read_socket_with_timeout: timeout "
" read for client %s. select error = %s. \n " ,
2007-11-04 09:20:10 +03:00
get_peer_addr ( fd , addr , sizeof ( addr ) ) ,
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
} else {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " read_socket_with_timeout: timeout "
" read. select error = %s. \n " ,
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
}
2008-01-24 21:17:14 +03:00
return map_nt_error_from_unix ( errno ) ;
2002-01-13 15:33:42 +03:00
}
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
/* Did we timeout ? */
if ( selrtn = = 0 ) {
2007-10-02 23:50:53 +04:00
DEBUG ( 10 , ( " read_socket_with_timeout: timeout read. "
" select timed out. \n " ) ) ;
2008-01-24 21:17:14 +03:00
return NT_STATUS_IO_TIMEOUT ;
2002-01-13 15:33:42 +03:00
}
2007-10-02 23:50:53 +04:00
2002-07-15 14:35:28 +04:00
readret = sys_read ( fd , buf + nread , maxcnt - nread ) ;
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
if ( readret = = 0 ) {
/* we got EOF on the file descriptor */
2007-10-02 23:50:53 +04:00
DEBUG ( 5 , ( " read_socket_with_timeout: timeout read. "
" EOF from client. \n " ) ) ;
2008-01-24 21:17:14 +03:00
return NT_STATUS_END_OF_FILE ;
2002-01-13 15:33:42 +03:00
}
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
if ( readret = = - 1 ) {
/* the descriptor is probably dead */
2007-11-04 09:20:10 +03:00
if ( fd = = get_client_fd ( ) ) {
2007-10-02 23:50:53 +04:00
/* Try and give an error message
* saying what client failed . */
DEBUG ( 0 , ( " read_socket_with_timeout: timeout "
" read to client %s. read error = %s. \n " ,
2007-11-04 09:20:10 +03:00
get_peer_addr ( fd , addr , sizeof ( addr ) ) ,
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
} else {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " read_socket_with_timeout: timeout "
" read. read error = %s. \n " ,
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
}
2008-01-24 21:17:14 +03:00
return map_nt_error_from_unix ( errno ) ;
2002-01-13 15:33:42 +03:00
}
2007-10-02 23:50:53 +04:00
2002-01-13 15:33:42 +03:00
nread + = readret ;
}
2007-10-02 23:50:53 +04:00
2008-01-24 21:17:14 +03:00
done :
2002-01-13 15:33:42 +03:00
/* Return the number we got */
2008-01-24 21:17:14 +03:00
if ( size_ret ) {
* size_ret = nread ;
}
return NT_STATUS_OK ;
}
2008-01-26 01:41:48 +03:00
/****************************************************************************
Read data from the client , reading exactly N bytes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-01-26 12:39:21 +03:00
NTSTATUS read_data ( int fd , char * buffer , size_t N )
2008-01-24 21:17:14 +03:00
{
2008-01-26 12:39:21 +03:00
return read_socket_with_timeout ( fd , buffer , N , N , 0 , NULL ) ;
1998-11-09 19:40:38 +03:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Write data to a fd .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2005-05-18 22:02:15 +04:00
ssize_t write_data ( int fd , const char * buffer , size_t N )
1998-11-09 19:40:38 +03:00
{
2002-07-15 14:35:28 +04:00
size_t total = 0 ;
ssize_t ret ;
2007-11-04 09:20:10 +03:00
char addr [ INET6_ADDRSTRLEN ] ;
1999-12-13 16:27:58 +03:00
2002-07-15 14:35:28 +04:00
while ( total < N ) {
ret = sys_write ( fd , buffer + total , N - total ) ;
if ( ret = = - 1 ) {
2007-11-04 09:20:10 +03:00
if ( fd = = get_client_fd ( ) ) {
2007-10-02 23:50:53 +04:00
/* Try and give an error message saying
* what client failed . */
DEBUG ( 0 , ( " write_data: write failure in "
" writing to client %s. Error %s \n " ,
2007-11-04 09:20:10 +03:00
get_peer_addr ( fd , addr , sizeof ( addr ) ) ,
strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
} else {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " write_data: write failure. "
" Error = %s \n " , strerror ( errno ) ) ) ;
2005-06-14 02:26:08 +04:00
}
2002-07-15 14:35:28 +04:00
return - 1 ;
}
2005-06-14 02:26:08 +04:00
if ( ret = = 0 ) {
2002-07-15 14:35:28 +04:00
return total ;
2005-06-14 02:26:08 +04:00
}
2002-07-15 14:35:28 +04:00
total + = ret ;
}
return ( ssize_t ) total ;
1998-11-09 19:40:38 +03:00
}
2002-07-15 14:35:28 +04:00
/****************************************************************************
2003-07-17 01:06:21 +04:00
Send a keepalive packet ( rfc1002 ) .
2002-07-15 14:35:28 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2007-10-11 05:25:16 +04:00
bool send_keepalive ( int client )
2002-07-15 14:35:28 +04:00
{
unsigned char buf [ 4 ] ;
buf [ 0 ] = SMBkeepalive ;
buf [ 1 ] = buf [ 2 ] = buf [ 3 ] = 0 ;
2005-06-14 02:26:08 +04:00
return ( write_data ( client , ( char * ) buf , 4 ) = = 4 ) ;
1999-12-13 16:27:58 +03:00
}
1998-11-09 19:40:38 +03:00
/****************************************************************************
2003-07-17 01:06:21 +04:00
Read 4 bytes of a smb packet and return the smb length of the packet .
Store the result in the buffer .
This version of the function will return a length of zero on receiving
a keepalive packet .
Timeout is in milliseconds .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2008-01-25 23:24:48 +03:00
NTSTATUS read_smb_length_return_keepalive ( int fd , char * inbuf ,
unsigned int timeout ,
size_t * len )
1998-11-09 19:40:38 +03:00
{
2002-07-15 14:35:28 +04:00
int msg_type ;
2008-01-25 23:02:52 +03:00
NTSTATUS status ;
2008-01-26 01:43:50 +03:00
status = read_socket_with_timeout ( fd , inbuf , 4 , 4 , timeout , NULL ) ;
2008-01-25 23:02:52 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-25 23:24:48 +03:00
return status ;
2008-01-25 11:21:44 +03:00
}
1998-11-09 19:40:38 +03:00
2008-01-25 23:24:48 +03:00
* len = smb_len ( inbuf ) ;
2008-01-25 11:21:44 +03:00
msg_type = CVAL ( inbuf , 0 ) ;
1998-11-09 19:40:38 +03:00
2008-01-25 11:21:44 +03:00
if ( msg_type = = SMBkeepalive ) {
DEBUG ( 5 , ( " Got keepalive packet \n " ) ) ;
2002-07-15 14:35:28 +04:00
}
1998-11-09 19:40:38 +03:00
2008-02-06 00:17:20 +03:00
DEBUG ( 10 , ( " got smb length of %lu \n " , ( unsigned long ) ( * len ) ) ) ;
1998-11-09 19:40:38 +03:00
2008-01-25 23:24:48 +03:00
return NT_STATUS_OK ;
1998-11-09 19:40:38 +03:00
}
/****************************************************************************
2003-07-17 01:06:21 +04:00
Read 4 bytes of a smb packet and return the smb length of the packet .
Store the result in the buffer . This version of the function will
never return a session keepalive ( length of zero ) .
Timeout is in milliseconds .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2008-01-25 23:31:40 +03:00
NTSTATUS read_smb_length ( int fd , char * inbuf , unsigned int timeout ,
size_t * len )
1998-11-09 19:40:38 +03:00
{
2008-01-25 11:28:19 +03:00
uint8_t msgtype = SMBkeepalive ;
1998-11-09 19:40:38 +03:00
2008-01-25 11:28:19 +03:00
while ( msgtype = = SMBkeepalive ) {
2008-01-25 23:24:48 +03:00
NTSTATUS status ;
status = read_smb_length_return_keepalive ( fd , inbuf , timeout ,
2008-01-25 23:31:40 +03:00
len ) ;
2008-01-25 23:24:48 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-25 23:31:40 +03:00
return status ;
2008-01-25 11:28:19 +03:00
}
2008-01-25 23:24:48 +03:00
2008-01-25 11:28:19 +03:00
msgtype = CVAL ( inbuf , 0 ) ;
2002-07-15 14:35:28 +04:00
}
1998-11-09 19:40:38 +03:00
2003-11-03 17:34:25 +03:00
DEBUG ( 10 , ( " read_smb_length: got smb length of %lu \n " ,
( unsigned long ) len ) ) ;
1999-12-13 16:27:58 +03:00
2008-01-25 23:31:40 +03:00
return NT_STATUS_OK ;
1998-11-09 19:40:38 +03:00
}
/****************************************************************************
2008-05-28 20:31:42 +04:00
Read an smb from a fd .
2007-10-02 23:50:53 +04:00
The timeout is in milliseconds .
2003-07-17 01:06:21 +04:00
This function will return on receipt of a session keepalive packet .
2007-05-16 04:07:38 +04:00
maxlen is the max number of bytes to return , not including the 4 byte
2008-05-28 20:31:42 +04:00
length . If zero it means buflen limit .
2003-10-22 01:19:00 +04:00
Doesn ' t check the MAC on signed packets .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2008-05-28 20:31:42 +04:00
NTSTATUS receive_smb_raw ( int fd , char * buffer , size_t buflen , unsigned int timeout ,
2008-01-26 01:54:22 +03:00
size_t maxlen , size_t * p_len )
1998-11-09 19:40:38 +03:00
{
2008-01-25 23:24:48 +03:00
size_t len ;
NTSTATUS status ;
1998-11-09 19:40:38 +03:00
2008-01-25 23:24:48 +03:00
status = read_smb_length_return_keepalive ( fd , buffer , timeout , & len ) ;
2002-02-24 00:03:21 +03:00
2008-01-25 23:24:48 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " receive_smb_raw: %s! \n " , nt_errstr ( status ) ) ) ;
2008-01-26 01:54:22 +03:00
return status ;
2001-05-24 23:28:22 +04:00
}
1998-11-09 19:40:38 +03:00
2008-05-28 20:31:42 +04:00
if ( len > buflen ) {
2007-10-02 23:50:53 +04:00
DEBUG ( 0 , ( " Invalid packet length! (%lu bytes). \n " ,
( unsigned long ) len ) ) ;
2008-05-28 20:31:42 +04:00
return NT_STATUS_INVALID_PARAMETER ;
2001-05-24 23:28:22 +04:00
}
if ( len > 0 ) {
2007-05-16 04:07:38 +04:00
if ( maxlen ) {
len = MIN ( len , maxlen ) ;
}
2008-01-26 01:43:50 +03:00
status = read_socket_with_timeout (
2008-01-26 01:41:48 +03:00
fd , buffer + 4 , len , len , timeout , & len ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-26 01:54:22 +03:00
return status ;
2001-05-24 23:28:22 +04:00
}
2007-10-02 23:50:53 +04:00
/* not all of samba3 properly checks for packet-termination
* of strings . This ensures that we don ' t run off into
* empty space . */
2005-05-27 21:47:24 +04:00
SSVAL ( buffer + 4 , len , 0 ) ;
2001-05-24 23:28:22 +04:00
}
2008-01-26 01:54:22 +03:00
* p_len = len ;
return NT_STATUS_OK ;
2003-10-22 01:19:00 +04:00
}
1998-11-09 19:40:38 +03:00
/****************************************************************************
2001-08-26 23:11:33 +04:00
Open a socket of the specified type , port , and address for incoming data .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2007-10-02 23:50:53 +04:00
int open_socket_in ( int type ,
2007-10-25 01:16:54 +04:00
uint16_t port ,
2007-10-02 23:50:53 +04:00
int dlevel ,
2007-10-25 01:16:54 +04:00
const struct sockaddr_storage * psock ,
bool rebind )
2001-08-26 23:11:33 +04:00
{
2007-10-25 01:16:54 +04:00
struct sockaddr_storage sock ;
2001-08-26 23:11:33 +04:00
int res ;
2007-11-03 00:22:19 +03:00
socklen_t slen = sizeof ( struct sockaddr_in ) ;
1998-11-09 19:40:38 +03:00
2007-10-25 01:16:54 +04:00
sock = * psock ;
1998-11-09 19:40:38 +03:00
2007-10-25 01:16:54 +04:00
# if defined(HAVE_IPV6)
if ( sock . ss_family = = AF_INET6 ) {
( ( struct sockaddr_in6 * ) & sock ) - > sin6_port = htons ( port ) ;
2007-11-03 00:22:19 +03:00
slen = sizeof ( struct sockaddr_in6 ) ;
2007-10-25 01:16:54 +04:00
}
1998-11-09 19:40:38 +03:00
# endif
2007-10-25 01:16:54 +04:00
if ( sock . ss_family = = AF_INET ) {
( ( struct sockaddr_in * ) & sock ) - > sin_port = htons ( port ) ;
}
2001-08-26 23:11:33 +04:00
2007-10-25 01:16:54 +04:00
res = socket ( sock . ss_family , type , 0 ) ;
2001-08-26 23:11:33 +04:00
if ( res = = - 1 ) {
if ( DEBUGLVL ( 0 ) ) {
dbgtext ( " open_socket_in(): socket() call failed: " ) ;
dbgtext ( " %s \n " , strerror ( errno ) ) ;
}
return - 1 ;
}
2001-08-26 08:16:51 +04:00
2001-08-26 23:11:33 +04:00
/* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
{
int val = rebind ? 1 : 0 ;
2007-10-02 23:50:53 +04:00
if ( setsockopt ( res , SOL_SOCKET , SO_REUSEADDR ,
( char * ) & val , sizeof ( val ) ) = = - 1 ) {
2001-08-26 23:11:33 +04:00
if ( DEBUGLVL ( dlevel ) ) {
dbgtext ( " open_socket_in(): setsockopt: " ) ;
2007-10-02 23:50:53 +04:00
dbgtext ( " SO_REUSEADDR = %s " ,
2007-10-11 05:25:16 +04:00
val ? " true " : " false " ) ;
2001-08-26 23:11:33 +04:00
dbgtext ( " on port %d failed " , port ) ;
dbgtext ( " with error = %s \n " , strerror ( errno ) ) ;
}
}
2000-02-17 01:48:19 +03:00
# ifdef SO_REUSEPORT
2007-10-02 23:50:53 +04:00
if ( setsockopt ( res , SOL_SOCKET , SO_REUSEPORT ,
( char * ) & val , sizeof ( val ) ) = = - 1 ) {
2001-08-26 23:11:33 +04:00
if ( DEBUGLVL ( dlevel ) ) {
2001-08-28 05:28:01 +04:00
dbgtext ( " open_socket_in(): setsockopt: " ) ;
2007-10-02 23:50:53 +04:00
dbgtext ( " SO_REUSEPORT = %s " ,
2007-10-25 01:16:54 +04:00
val ? " true " : " false " ) ;
dbgtext ( " on port %d failed " , port ) ;
dbgtext ( " with error = %s \n " , strerror ( errno ) ) ;
2001-08-26 23:11:33 +04:00
}
}
2000-02-17 01:48:19 +03:00
# endif /* SO_REUSEPORT */
2001-08-26 23:11:33 +04:00
}
1998-11-09 19:40:38 +03:00
2001-08-26 23:11:33 +04:00
/* now we've got a socket - we need to bind it */
2007-11-03 00:22:19 +03:00
if ( bind ( res , ( struct sockaddr * ) & sock , slen ) = = - 1 ) {
2007-10-02 23:50:53 +04:00
if ( DEBUGLVL ( dlevel ) & & ( port = = SMB_PORT1 | |
port = = SMB_PORT2 | | port = = NMB_PORT ) ) {
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
print_sockaddr ( addr , sizeof ( addr ) ,
& sock ) ;
dbgtext ( " bind failed on port %d " , port ) ;
dbgtext ( " socket_addr = %s. \n " , addr ) ;
dbgtext ( " Error = %s \n " , strerror ( errno ) ) ;
2001-08-26 23:11:33 +04:00
}
2007-10-25 01:16:54 +04:00
close ( res ) ;
2007-10-02 23:50:53 +04:00
return - 1 ;
2001-08-26 23:11:33 +04:00
}
1998-11-09 19:40:38 +03:00
2002-07-15 14:35:28 +04:00
DEBUG ( 10 , ( " bind succeeded on port %d \n " , port ) ) ;
2001-08-26 23:11:33 +04:00
return ( res ) ;
}
1998-11-09 19:40:38 +03:00
/****************************************************************************
2003-07-17 01:06:21 +04:00
Create an outgoing socket . timeout is in milliseconds .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2007-10-25 01:16:54 +04:00
int open_socket_out ( int type ,
const struct sockaddr_storage * pss ,
uint16_t port ,
int timeout )
1998-11-09 19:40:38 +03:00
{
2007-10-25 01:16:54 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
struct sockaddr_storage sock_out = * pss ;
2003-07-17 01:06:21 +04:00
int res , ret ;
int connect_loop = 10 ;
int increment = 10 ;
1998-11-09 19:40:38 +03:00
2003-07-17 01:06:21 +04:00
/* create a socket to write to */
2007-10-25 01:16:54 +04:00
res = socket ( pss - > ss_family , type , 0 ) ;
2003-07-17 01:06:21 +04:00
if ( res = = - 1 ) {
2004-03-19 19:22:47 +03:00
DEBUG ( 0 , ( " socket error (%s) \n " , strerror ( errno ) ) ) ;
2003-07-17 01:06:21 +04:00
return - 1 ;
}
1998-11-09 19:40:38 +03:00
2007-10-25 01:16:54 +04:00
if ( type ! = SOCK_STREAM ) {
return res ;
}
2007-10-02 23:50:53 +04:00
2007-10-25 01:16:54 +04:00
# if defined(HAVE_IPV6)
if ( pss - > ss_family = = AF_INET6 ) {
struct sockaddr_in6 * psa6 = ( struct sockaddr_in6 * ) & sock_out ;
psa6 - > sin6_port = htons ( port ) ;
2007-10-26 05:28:36 +04:00
if ( psa6 - > sin6_scope_id = = 0 & &
IN6_IS_ADDR_LINKLOCAL ( & psa6 - > sin6_addr ) ) {
setup_linklocal_scope_id ( & sock_out ) ;
}
2007-10-25 01:16:54 +04:00
}
# endif
if ( pss - > ss_family = = AF_INET ) {
struct sockaddr_in * psa = ( struct sockaddr_in * ) & sock_out ;
psa - > sin_port = htons ( port ) ;
}
1998-11-09 19:40:38 +03:00
2003-07-17 01:06:21 +04:00
/* set it non-blocking */
2007-10-11 05:25:16 +04:00
set_blocking ( res , false ) ;
1998-11-09 19:40:38 +03:00
2007-10-25 01:16:54 +04:00
print_sockaddr ( addr , sizeof ( addr ) , & sock_out ) ;
DEBUG ( 3 , ( " Connecting to %s at port %u \n " ,
addr ,
( unsigned int ) port ) ) ;
2007-10-02 23:50:53 +04:00
2003-07-17 01:06:21 +04:00
/* and connect it to the destination */
connect_again :
2007-12-10 00:28:00 +03:00
ret = sys_connect ( res , ( struct sockaddr * ) & sock_out ) ;
2003-07-17 01:06:21 +04:00
/* Some systems return EAGAIN when they mean EINPROGRESS */
if ( ret < 0 & & ( errno = = EINPROGRESS | | errno = = EALREADY | |
errno = = EAGAIN ) & & ( connect_loop < timeout ) ) {
2004-02-23 05:54:03 +03:00
smb_msleep ( connect_loop ) ;
2004-04-30 17:58:23 +04:00
timeout - = connect_loop ;
2003-07-17 01:06:21 +04:00
connect_loop + = increment ;
if ( increment < 250 ) {
/* After 8 rounds we end up at a max of 255 msec */
increment * = 1.5 ;
}
goto connect_again ;
}
if ( ret < 0 & & ( errno = = EINPROGRESS | | errno = = EALREADY | |
errno = = EAGAIN ) ) {
2007-10-25 01:16:54 +04:00
DEBUG ( 1 , ( " timeout connecting to %s:%u \n " ,
addr ,
( unsigned int ) port ) ) ;
2003-07-17 01:06:21 +04:00
close ( res ) ;
return - 1 ;
}
1998-11-09 19:40:38 +03:00
# ifdef EISCONN
2003-07-17 01:06:21 +04:00
if ( ret < 0 & & errno = = EISCONN ) {
errno = 0 ;
ret = 0 ;
}
1998-11-09 19:40:38 +03:00
# endif
2003-07-17 01:06:21 +04:00
if ( ret < 0 ) {
DEBUG ( 2 , ( " error connecting to %s:%d (%s) \n " ,
2007-10-25 01:16:54 +04:00
addr ,
( unsigned int ) port ,
strerror ( errno ) ) ) ;
2003-07-17 01:06:21 +04:00
close ( res ) ;
return - 1 ;
}
1998-11-09 19:40:38 +03:00
2003-07-17 01:06:21 +04:00
/* set it blocking again */
2007-10-11 05:25:16 +04:00
set_blocking ( res , true ) ;
1998-11-09 19:40:38 +03:00
2003-07-17 01:06:21 +04:00
return res ;
1998-11-09 19:40:38 +03:00
}
2008-09-04 02:31:39 +04:00
/*******************************************************************
Create an outgoing TCP socket to the first addr that connects .
This is for simultaneous connection attempts to port 445 and 139 of a host
or for simultatneous connection attempts to multiple DCs at once . We return
a socket fd of the first successful connection .
@ param [ in ] addrs list of Internet addresses and ports to connect to
@ param [ in ] num_addrs number of address / port pairs in the addrs list
@ param [ in ] timeout time after which we stop waiting for a socket connection
to succeed , given in milliseconds
@ param [ out ] fd_index the entry in addrs which we successfully connected to
@ param [ out ] fd fd of the open and connected socket
@ return true on a successful connection , false if all connection attempts
failed or we timed out
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-11-18 14:57:49 +03:00
2007-10-25 01:16:54 +04:00
bool open_any_socket_out ( struct sockaddr_storage * addrs , int num_addrs ,
2004-11-18 14:57:49 +03:00
int timeout , int * fd_index , int * fd )
{
int i , resulting_index , res ;
int * sockets ;
2007-10-11 05:25:16 +04:00
bool good_connect ;
2004-11-18 14:57:49 +03:00
2004-12-15 15:05:48 +03:00
fd_set r_fds , wr_fds ;
2004-11-18 14:57:49 +03:00
struct timeval tv ;
int maxfd ;
int connect_loop = 10000 ; /* 10 milliseconds */
timeout * = 1000 ; /* convert to microseconds */
2004-12-07 21:25:53 +03:00
sockets = SMB_MALLOC_ARRAY ( int , num_addrs ) ;
2004-11-18 14:57:49 +03:00
if ( sockets = = NULL )
2007-10-11 05:25:16 +04:00
return false ;
2004-11-18 14:57:49 +03:00
resulting_index = - 1 ;
for ( i = 0 ; i < num_addrs ; i + + )
sockets [ i ] = - 1 ;
for ( i = 0 ; i < num_addrs ; i + + ) {
2007-10-25 01:16:54 +04:00
sockets [ i ] = socket ( addrs [ i ] . ss_family , SOCK_STREAM , 0 ) ;
2004-11-18 14:57:49 +03:00
if ( sockets [ i ] < 0 )
goto done ;
2007-10-11 05:25:16 +04:00
set_blocking ( sockets [ i ] , false ) ;
2004-11-18 14:57:49 +03:00
}
connect_again :
2007-10-11 05:25:16 +04:00
good_connect = false ;
2004-11-18 14:57:49 +03:00
for ( i = 0 ; i < num_addrs ; i + + ) {
2007-12-10 00:28:00 +03:00
const struct sockaddr * a =
( const struct sockaddr * ) & ( addrs [ i ] ) ;
2004-11-18 14:57:49 +03:00
2004-12-15 15:05:48 +03:00
if ( sockets [ i ] = = - 1 )
continue ;
2007-12-10 00:28:00 +03:00
if ( sys_connect ( sockets [ i ] , a ) = = 0 ) {
2004-11-18 14:57:49 +03:00
/* Rather unlikely as we are non-blocking, but it
* might actually happen . */
resulting_index = i ;
goto done ;
}
if ( errno = = EINPROGRESS | | errno = = EALREADY | |
2007-04-12 05:09:19 +04:00
# ifdef EISCONN
errno = = EISCONN | |
# endif
2006-12-13 08:54:39 +03:00
errno = = EAGAIN | | errno = = EINTR ) {
2004-11-18 14:57:49 +03:00
/* These are the error messages that something is
progressing . */
2007-10-11 05:25:16 +04:00
good_connect = true ;
2004-12-15 15:05:48 +03:00
} else if ( errno ! = 0 ) {
/* There was a direct error */
close ( sockets [ i ] ) ;
sockets [ i ] = - 1 ;
2004-11-18 14:57:49 +03:00
}
}
if ( ! good_connect ) {
/* All of the connect's resulted in real error conditions */
goto done ;
}
/* Lets see if any of the connect attempts succeeded */
maxfd = 0 ;
FD_ZERO ( & wr_fds ) ;
2004-12-15 15:05:48 +03:00
FD_ZERO ( & r_fds ) ;
2004-11-18 14:57:49 +03:00
for ( i = 0 ; i < num_addrs ; i + + ) {
2004-12-15 15:05:48 +03:00
if ( sockets [ i ] = = - 1 )
continue ;
2004-11-18 14:57:49 +03:00
FD_SET ( sockets [ i ] , & wr_fds ) ;
2004-12-15 15:05:48 +03:00
FD_SET ( sockets [ i ] , & r_fds ) ;
2004-11-18 14:57:49 +03:00
if ( sockets [ i ] > maxfd )
maxfd = sockets [ i ] ;
}
tv . tv_sec = 0 ;
tv . tv_usec = connect_loop ;
2006-05-18 05:30:00 +04:00
res = sys_select_intr ( maxfd + 1 , & r_fds , & wr_fds , NULL , & tv ) ;
2004-11-18 14:57:49 +03:00
if ( res < 0 )
goto done ;
if ( res = = 0 )
goto next_round ;
for ( i = 0 ; i < num_addrs ; i + + ) {
2004-12-15 15:05:48 +03:00
if ( sockets [ i ] = = - 1 )
2004-11-18 14:57:49 +03:00
continue ;
2004-12-15 15:05:48 +03:00
/* Stevens, Network Programming says that if there's a
* successful connect , the socket is only writable . Upon an
* error , it ' s both readable and writable . */
2004-11-18 14:57:49 +03:00
2004-12-15 15:05:48 +03:00
if ( FD_ISSET ( sockets [ i ] , & r_fds ) & &
FD_ISSET ( sockets [ i ] , & wr_fds ) ) {
/* readable and writable, so it's an error */
close ( sockets [ i ] ) ;
sockets [ i ] = - 1 ;
continue ;
}
2004-11-18 14:57:49 +03:00
2004-12-15 15:05:48 +03:00
if ( ! FD_ISSET ( sockets [ i ] , & r_fds ) & &
FD_ISSET ( sockets [ i ] , & wr_fds ) ) {
/* Only writable, so it's connected */
2004-11-18 14:57:49 +03:00
resulting_index = i ;
goto done ;
}
}
next_round :
timeout - = connect_loop ;
if ( timeout < = 0 )
goto done ;
connect_loop * = 1.5 ;
if ( connect_loop > timeout )
connect_loop = timeout ;
goto connect_again ;
done :
for ( i = 0 ; i < num_addrs ; i + + ) {
if ( i = = resulting_index )
continue ;
if ( sockets [ i ] > = 0 )
close ( sockets [ i ] ) ;
}
if ( resulting_index > = 0 ) {
* fd_index = resulting_index ;
* fd = sockets [ * fd_index ] ;
2007-10-11 05:25:16 +04:00
set_blocking ( * fd , true ) ;
2004-11-18 14:57:49 +03:00
}
free ( sockets ) ;
return ( resulting_index > = 0 ) ;
}
2003-07-17 01:06:21 +04:00
/****************************************************************************
Open a connected UDP socket to host on port
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-24 17:16:41 +03:00
int open_udp_socket ( const char * host , int port )
{
int type = SOCK_DGRAM ;
struct sockaddr_in sock_out ;
int res ;
2007-11-04 08:34:46 +03:00
struct in_addr addr ;
2001-11-24 17:16:41 +03:00
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & addr , host ) ;
2001-11-24 17:16:41 +03:00
res = socket ( PF_INET , type , 0 ) ;
if ( res = = - 1 ) {
return - 1 ;
}
memset ( ( char * ) & sock_out , ' \0 ' , sizeof ( sock_out ) ) ;
2007-11-04 08:34:46 +03:00
putip ( ( char * ) & sock_out . sin_addr , ( char * ) & addr ) ;
2001-11-24 17:16:41 +03:00
sock_out . sin_port = htons ( port ) ;
sock_out . sin_family = PF_INET ;
2007-12-10 00:28:00 +03:00
if ( sys_connect ( res , ( struct sockaddr * ) & sock_out ) ) {
2001-11-24 17:16:41 +03:00
close ( res ) ;
return - 1 ;
}
return res ;
}
2007-10-13 00:38:04 +04:00
/*******************************************************************
Return the IP addr of the remote end of a socket as a string .
Optionally return the struct sockaddr_storage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const char * get_peer_addr_internal ( int fd ,
2007-11-04 04:41:26 +03:00
char * addr_buf ,
size_t addr_buf_len ,
2007-10-13 00:38:04 +04:00
struct sockaddr_storage * pss ,
socklen_t * plength )
{
struct sockaddr_storage ss ;
socklen_t length = sizeof ( ss ) ;
2007-11-07 23:48:58 +03:00
strlcpy ( addr_buf , " 0.0.0.0 " , addr_buf_len ) ;
2007-10-13 00:38:04 +04:00
if ( fd = = - 1 ) {
return addr_buf ;
}
if ( pss = = NULL ) {
pss = & ss ;
}
if ( plength = = NULL ) {
plength = & length ;
}
if ( getpeername ( fd , ( struct sockaddr * ) pss , plength ) < 0 ) {
DEBUG ( 0 , ( " getpeername failed. Error was %s \n " ,
strerror ( errno ) ) ) ;
return addr_buf ;
}
2007-10-25 01:16:54 +04:00
print_sockaddr_len ( addr_buf ,
2007-11-04 06:27:59 +03:00
addr_buf_len ,
2007-10-13 00:38:04 +04:00
pss ,
* plength ) ;
return addr_buf ;
}
1998-11-09 19:40:38 +03:00
/*******************************************************************
2003-07-17 01:06:21 +04:00
Matchname - determine if host name matches IP address . Used to
confirm a hostname lookup to prevent spoof attacks .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-13 00:38:04 +04:00
static bool matchname ( const char * remotehost ,
const struct sockaddr_storage * pss ,
socklen_t len )
1998-11-09 19:40:38 +03:00
{
2007-10-13 00:38:04 +04:00
struct addrinfo * res = NULL ;
struct addrinfo * ailist = NULL ;
char addr_buf [ INET6_ADDRSTRLEN ] ;
2007-10-16 03:11:48 +04:00
bool ret = interpret_string_addr_internal ( & ailist ,
remotehost ,
AI_ADDRCONFIG | AI_CANONNAME ) ;
2007-10-13 00:38:04 +04:00
2007-10-16 03:11:48 +04:00
if ( ! ret | | ailist = = NULL ) {
2007-10-13 00:38:04 +04:00
DEBUG ( 3 , ( " matchname: getaddrinfo failed for "
" name %s [%s] \n " ,
remotehost ,
gai_strerror ( ret ) ) ) ;
2007-10-11 05:25:16 +04:00
return false ;
2007-10-02 23:50:53 +04:00
}
2000-04-11 17:55:53 +04:00
/*
2007-10-13 00:38:04 +04:00
* Make sure that getaddrinfo ( ) returns the " correct " host name .
2000-04-11 17:55:53 +04:00
*/
2007-10-02 23:50:53 +04:00
2007-10-16 03:11:48 +04:00
if ( ailist - > ai_canonname = = NULL | |
( ! strequal ( remotehost , ailist - > ai_canonname ) & &
2007-10-13 00:38:04 +04:00
! strequal ( remotehost , " localhost " ) ) ) {
DEBUG ( 0 , ( " matchname: host name/name mismatch: %s != %s \n " ,
remotehost ,
2007-10-16 03:11:48 +04:00
ailist - > ai_canonname ?
ailist - > ai_canonname : " (NULL) " ) ) ;
freeaddrinfo ( ailist ) ;
2007-10-11 05:25:16 +04:00
return false ;
1998-11-09 19:40:38 +03:00
}
2007-10-02 23:50:53 +04:00
2000-04-11 17:55:53 +04:00
/* Look up the host address in the address list we just got. */
2007-10-16 03:11:48 +04:00
for ( res = ailist ; res ; res = res - > ai_next ) {
if ( ! res - > ai_addr ) {
2007-10-13 00:38:04 +04:00
continue ;
}
2007-10-16 03:11:48 +04:00
if ( addr_equal ( ( const struct sockaddr_storage * ) res - > ai_addr ,
2007-10-13 00:38:04 +04:00
pss ) ) {
2007-10-16 03:11:48 +04:00
freeaddrinfo ( ailist ) ;
2007-10-11 05:25:16 +04:00
return true ;
2007-10-13 00:38:04 +04:00
}
1998-11-09 19:40:38 +03:00
}
2007-10-02 23:50:53 +04:00
2000-04-11 17:55:53 +04:00
/*
* The host name does not map to the original host address . Perhaps
* someone has compromised a name server . More likely someone botched
* it , but that could be dangerous , too .
*/
2007-10-02 23:50:53 +04:00
2007-10-13 00:38:04 +04:00
DEBUG ( 0 , ( " matchname: host name/address mismatch: %s != %s \n " ,
2007-10-25 01:16:54 +04:00
print_sockaddr_len ( addr_buf ,
2007-10-13 00:38:04 +04:00
sizeof ( addr_buf ) ,
pss ,
len ) ,
2007-10-16 03:11:48 +04:00
ailist - > ai_canonname ? ailist - > ai_canonname : " (NULL) " ) ) ;
2007-10-13 00:38:04 +04:00
2007-10-16 03:11:48 +04:00
if ( ailist ) {
freeaddrinfo ( ailist ) ;
}
2007-10-11 05:25:16 +04:00
return false ;
2000-04-11 17:55:53 +04:00
}
2008-01-03 04:37:39 +03:00
/*******************************************************************
Deal with the singleton cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct name_addr_pair {
struct sockaddr_storage ss ;
const char * name ;
} ;
/*******************************************************************
Lookup a name / addr pair . Returns memory allocated from memcache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool lookup_nc ( struct name_addr_pair * nc )
{
DATA_BLOB tmp ;
ZERO_STRUCTP ( nc ) ;
if ( ! memcache_lookup (
NULL , SINGLETON_CACHE ,
data_blob_string_const ( " get_peer_name " ) ,
& tmp ) ) {
return false ;
}
memcpy ( & nc - > ss , tmp . data , sizeof ( nc - > ss ) ) ;
nc - > name = ( const char * ) tmp . data + sizeof ( nc - > ss ) ;
return true ;
}
/*******************************************************************
Save a name / addr pair .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void store_nc ( const struct name_addr_pair * nc )
{
DATA_BLOB tmp ;
size_t namelen = strlen ( nc - > name ) ;
2008-01-03 12:24:45 +03:00
tmp = data_blob ( NULL , sizeof ( nc - > ss ) + namelen + 1 ) ;
2008-01-03 04:37:39 +03:00
if ( ! tmp . data ) {
return ;
}
memcpy ( tmp . data , & nc - > ss , sizeof ( nc - > ss ) ) ;
memcpy ( tmp . data + sizeof ( nc - > ss ) , nc - > name , namelen + 1 ) ;
memcache_add ( NULL , SINGLETON_CACHE ,
data_blob_string_const ( " get_peer_name " ) ,
tmp ) ;
2008-01-03 12:24:45 +03:00
data_blob_free ( & tmp ) ;
2008-01-03 04:37:39 +03:00
}
2007-11-07 23:48:58 +03:00
2000-04-11 17:55:53 +04:00
/*******************************************************************
2003-07-17 01:06:21 +04:00
Return the DNS name of the remote end of a socket .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-01-03 04:37:39 +03:00
const char * get_peer_name ( int fd , bool force_lookup )
2000-04-11 17:55:53 +04:00
{
2008-01-03 04:37:39 +03:00
struct name_addr_pair nc ;
2007-11-04 04:15:45 +03:00
char addr_buf [ INET6_ADDRSTRLEN ] ;
2007-10-13 00:38:04 +04:00
struct sockaddr_storage ss ;
socklen_t length = sizeof ( ss ) ;
2007-10-12 02:36:13 +04:00
const char * p ;
2007-10-13 00:38:04 +04:00
int ret ;
2007-11-16 05:27:26 +03:00
char name_buf [ MAX_DNS_NAME_LENGTH ] ;
char tmp_name [ MAX_DNS_NAME_LENGTH ] ;
2001-09-13 04:30:47 +04:00
/* reverse lookups can be *very* expensive, and in many
situations won ' t work because many networks don ' t link dhcp
with dns . To avoid the delay we avoid the lookup if
possible */
2007-10-11 05:25:16 +04:00
if ( ! lp_hostname_lookups ( ) & & ( force_lookup = = false ) ) {
2007-11-07 23:48:58 +03:00
length = sizeof ( nc . ss ) ;
2008-01-03 04:37:39 +03:00
nc . name = get_peer_addr_internal ( fd , addr_buf , sizeof ( addr_buf ) ,
2007-11-07 23:48:58 +03:00
& nc . ss , & length ) ;
2008-01-03 04:37:39 +03:00
store_nc ( & nc ) ;
lookup_nc ( & nc ) ;
2007-11-07 23:48:58 +03:00
return nc . name ? nc . name : " UNKNOWN " ;
2001-09-13 04:30:47 +04:00
}
2007-10-02 23:50:53 +04:00
2008-01-03 04:37:39 +03:00
lookup_nc ( & nc ) ;
2007-11-07 23:48:58 +03:00
memset ( & ss , ' \0 ' , sizeof ( ss ) ) ;
2007-11-04 04:41:26 +03:00
p = get_peer_addr_internal ( fd , addr_buf , sizeof ( addr_buf ) , & ss , & length ) ;
2000-04-11 17:55:53 +04:00
/* it might be the same as the last one - save some DNS work */
2007-11-07 23:48:58 +03:00
if ( addr_equal ( & ss , & nc . ss ) ) {
return nc . name ? nc . name : " UNKNOWN " ;
2007-10-13 00:38:04 +04:00
}
2000-04-11 17:55:53 +04:00
2008-01-03 04:37:39 +03:00
/* Not the same. We need to lookup. */
2007-10-13 00:38:04 +04:00
if ( fd = = - 1 ) {
2007-11-07 23:48:58 +03:00
return " UNKNOWN " ;
2007-10-13 00:38:04 +04:00
}
2000-04-11 17:55:53 +04:00
1998-11-09 19:40:38 +03:00
/* Look up the remote host name. */
2008-01-17 00:21:46 +03:00
ret = sys_getnameinfo ( ( struct sockaddr * ) & ss ,
2007-10-13 00:38:04 +04:00
length ,
name_buf ,
sizeof ( name_buf ) ,
NULL ,
0 ,
2007-10-26 03:14:52 +04:00
0 ) ;
2007-10-13 00:38:04 +04:00
if ( ret ) {
DEBUG ( 1 , ( " get_peer_name: getnameinfo failed "
" for %s with error %s \n " ,
p ,
gai_strerror ( ret ) ) ) ;
2007-11-07 23:48:58 +03:00
strlcpy ( name_buf , p , sizeof ( name_buf ) ) ;
1998-11-09 19:40:38 +03:00
} else {
2007-10-13 00:38:04 +04:00
if ( ! matchname ( name_buf , & ss , length ) ) {
2000-04-11 17:55:53 +04:00
DEBUG ( 0 , ( " Matchname failed on %s %s \n " , name_buf , p ) ) ;
2007-11-07 23:48:58 +03:00
strlcpy ( name_buf , " UNKNOWN " , sizeof ( name_buf ) ) ;
1998-11-09 19:40:38 +03:00
}
}
2001-07-05 08:44:09 +04:00
2007-10-02 23:50:53 +04:00
/* can't pass the same source and dest strings in when you
use - - enable - developer or the clobber_region ( ) call will
2003-12-09 21:20:27 +03:00
get you */
2007-10-02 23:50:53 +04:00
2007-11-07 23:48:58 +03:00
strlcpy ( tmp_name , name_buf , sizeof ( tmp_name ) ) ;
2003-12-09 21:20:27 +03:00
alpha_strcpy ( name_buf , tmp_name , " _-. " , sizeof ( name_buf ) ) ;
2001-07-05 08:44:09 +04:00
if ( strstr ( name_buf , " .. " ) ) {
2007-11-07 23:48:58 +03:00
strlcpy ( name_buf , " UNKNOWN " , sizeof ( name_buf ) ) ;
2001-07-05 08:44:09 +04:00
}
2008-01-03 04:37:39 +03:00
nc . name = name_buf ;
nc . ss = ss ;
store_nc ( & nc ) ;
lookup_nc ( & nc ) ;
2007-11-07 23:48:58 +03:00
return nc . name ? nc . name : " UNKNOWN " ;
1998-11-09 19:40:38 +03:00
}
/*******************************************************************
2003-07-17 01:06:21 +04:00
Return the IP addr of the remote end of a socket as a string .
1998-11-09 19:40:38 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-07-17 01:06:21 +04:00
2007-11-04 04:41:26 +03:00
const char * get_peer_addr ( int fd , char * addr , size_t addr_len )
1998-11-09 19:40:38 +03:00
{
2007-11-04 04:41:26 +03:00
return get_peer_addr_internal ( fd , addr , addr_len , NULL , NULL ) ;
1998-11-09 19:40:38 +03:00
}
2000-01-03 22:19:48 +03:00
2002-01-13 14:13:54 +03:00
/*******************************************************************
Create protected unix domain socket .
2003-02-08 00:59:51 +03:00
Some unixes cannot set permissions on a ux - dom - sock , so we
2002-01-13 14:13:54 +03:00
have to make sure that the directory contains the protection
2003-02-08 00:59:51 +03:00
permissions instead .
2002-01-13 14:13:54 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-02-08 00:59:51 +03:00
2002-01-13 14:13:54 +03:00
int create_pipe_sock ( const char * socket_dir ,
2002-07-15 14:35:28 +04:00
const char * socket_name ,
mode_t dir_perms )
2002-01-13 14:13:54 +03:00
{
2002-09-25 19:19:00 +04:00
# ifdef HAVE_UNIXSOCKET
2003-02-08 00:59:51 +03:00
struct sockaddr_un sunaddr ;
struct stat st ;
int sock ;
mode_t old_umask ;
2007-11-12 08:45:55 +03:00
char * path = NULL ;
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
old_umask = umask ( 0 ) ;
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
/* Create the socket directory or reuse the existing one */
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
if ( lstat ( socket_dir , & st ) = = - 1 ) {
if ( errno = = ENOENT ) {
/* Create directory */
if ( mkdir ( socket_dir , dir_perms ) = = - 1 ) {
DEBUG ( 0 , ( " error creating socket directory "
2007-10-02 23:50:53 +04:00
" %s: %s \n " , socket_dir ,
2003-02-08 00:59:51 +03:00
strerror ( errno ) ) ) ;
goto out_umask ;
}
} else {
DEBUG ( 0 , ( " lstat failed on socket directory %s: %s \n " ,
socket_dir , strerror ( errno ) ) ) ;
goto out_umask ;
}
} else {
/* Check ownership and permission on existing directory */
if ( ! S_ISDIR ( st . st_mode ) ) {
DEBUG ( 0 , ( " socket directory %s isn't a directory \n " ,
socket_dir ) ) ;
goto out_umask ;
}
2007-10-02 23:50:53 +04:00
if ( ( st . st_uid ! = sec_initial_uid ( ) ) | |
2003-02-08 00:59:51 +03:00
( ( st . st_mode & 0777 ) ! = dir_perms ) ) {
DEBUG ( 0 , ( " invalid permissions on socket directory "
" %s \n " , socket_dir ) ) ;
goto out_umask ;
}
}
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
/* Create the socket file */
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
sock = socket ( AF_UNIX , SOCK_STREAM , 0 ) ;
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
if ( sock = = - 1 ) {
2007-11-12 08:45:55 +03:00
DEBUG ( 0 , ( " create_pipe_sock: socket error %s \n " ,
strerror ( errno ) ) ) ;
goto out_close ;
2003-02-08 00:59:51 +03:00
}
2007-10-02 23:50:53 +04:00
2008-02-25 17:24:49 +03:00
if ( asprintf ( & path , " %s/%s " , socket_dir , socket_name ) = = - 1 ) {
2007-11-12 08:45:55 +03:00
goto out_close ;
}
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
unlink ( path ) ;
memset ( & sunaddr , 0 , sizeof ( sunaddr ) ) ;
sunaddr . sun_family = AF_UNIX ;
2007-11-07 23:48:58 +03:00
strlcpy ( sunaddr . sun_path , path , sizeof ( sunaddr . sun_path ) ) ;
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
if ( bind ( sock , ( struct sockaddr * ) & sunaddr , sizeof ( sunaddr ) ) = = - 1 ) {
DEBUG ( 0 , ( " bind failed on pipe socket %s: %s \n " , path ,
strerror ( errno ) ) ) ;
goto out_close ;
}
2007-10-02 23:50:53 +04:00
2003-02-08 00:59:51 +03:00
if ( listen ( sock , 5 ) = = - 1 ) {
DEBUG ( 0 , ( " listen failed on pipe socket %s: %s \n " , path ,
strerror ( errno ) ) ) ;
goto out_close ;
}
2007-10-02 23:50:53 +04:00
2007-11-12 08:45:55 +03:00
SAFE_FREE ( path ) ;
2003-02-08 00:59:51 +03:00
umask ( old_umask ) ;
return sock ;
out_close :
2007-11-12 08:45:55 +03:00
SAFE_FREE ( path ) ;
2008-02-18 02:43:46 +03:00
if ( sock ! = - 1 )
close ( sock ) ;
2003-02-08 00:59:51 +03:00
out_umask :
umask ( old_umask ) ;
return - 1 ;
2002-09-25 19:19:00 +04:00
# else
DEBUG ( 0 , ( " create_pipe_sock: No Unix sockets on this system \n " ) ) ;
return - 1 ;
# endif /* HAVE_UNIXSOCKET */
2002-01-13 14:13:54 +03:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/****************************************************************************
Get my own canonical name , including domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-09 04:25:45 +03:00
const char * get_mydnsfullname ( void )
2007-10-16 03:11:48 +04:00
{
2008-01-03 04:37:39 +03:00
struct addrinfo * res = NULL ;
char my_hostname [ HOST_NAME_MAX ] ;
bool ret ;
DATA_BLOB tmp ;
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
if ( memcache_lookup ( NULL , SINGLETON_CACHE ,
data_blob_string_const ( " get_mydnsfullname " ) ,
& tmp ) ) {
SMB_ASSERT ( tmp . length > 0 ) ;
return ( const char * ) tmp . data ;
}
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
/* get my host name */
if ( gethostname ( my_hostname , sizeof ( my_hostname ) ) = = - 1 ) {
DEBUG ( 0 , ( " get_mydnsfullname: gethostname failed \n " ) ) ;
return NULL ;
}
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
/* Ensure null termination. */
my_hostname [ sizeof ( my_hostname ) - 1 ] = ' \0 ' ;
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
ret = interpret_string_addr_internal ( & res ,
2007-11-09 04:25:45 +03:00
my_hostname ,
2008-01-03 04:37:39 +03:00
AI_ADDRCONFIG | AI_CANONNAME ) ;
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
if ( ! ret | | res = = NULL ) {
DEBUG ( 3 , ( " get_mydnsfullname: getaddrinfo failed for "
" name %s [%s] \n " ,
my_hostname ,
gai_strerror ( ret ) ) ) ;
return NULL ;
}
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
/*
* Make sure that getaddrinfo ( ) returns the " correct " host name .
*/
2007-10-16 03:11:48 +04:00
2008-01-03 04:37:39 +03:00
if ( res - > ai_canonname = = NULL ) {
DEBUG ( 3 , ( " get_mydnsfullname: failed to get "
" canonical name for %s \n " ,
my_hostname ) ) ;
2007-10-16 03:11:48 +04:00
freeaddrinfo ( res ) ;
2008-01-03 04:37:39 +03:00
return NULL ;
}
/* This copies the data, so we must do a lookup
* afterwards to find the value to return .
*/
memcache_add ( NULL , SINGLETON_CACHE ,
data_blob_string_const ( " get_mydnsfullname " ) ,
data_blob_string_const ( res - > ai_canonname ) ) ;
if ( ! memcache_lookup ( NULL , SINGLETON_CACHE ,
data_blob_string_const ( " get_mydnsfullname " ) ,
& tmp ) ) {
2008-01-21 20:01:55 +03:00
tmp = data_blob_talloc ( talloc_tos ( ) , res - > ai_canonname ,
strlen ( res - > ai_canonname ) + 1 ) ;
2007-10-16 03:11:48 +04:00
}
2008-01-03 04:37:39 +03:00
2008-01-21 15:18:38 +03:00
freeaddrinfo ( res ) ;
2008-01-03 04:37:39 +03:00
return ( const char * ) tmp . data ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
/************************************************************
2007-10-16 03:11:48 +04:00
Is this my name ?
2007-10-11 05:25:16 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_myname_or_ipaddr ( const char * s )
{
2007-11-09 04:25:45 +03:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
char * name = NULL ;
const char * dnsname ;
char * servername = NULL ;
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
if ( ! s ) {
2007-10-11 05:25:16 +04:00
return false ;
2007-10-13 08:50:41 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* Santize the string from '\\name' */
2007-11-09 04:25:45 +03:00
name = talloc_strdup ( ctx , s ) ;
if ( ! name ) {
return false ;
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
servername = strrchr_m ( name , ' \\ ' ) ;
if ( ! servername ) {
2007-10-11 05:25:16 +04:00
servername = name ;
2007-10-16 03:11:48 +04:00
} else {
2007-10-11 05:25:16 +04:00
servername + + ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* Optimize for the common case */
if ( strequal ( servername , global_myname ( ) ) ) {
2007-10-11 05:25:16 +04:00
return true ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* Check for an alias */
if ( is_myname ( servername ) ) {
2007-10-11 05:25:16 +04:00
return true ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* Check for loopback */
if ( strequal ( servername , " 127.0.0.1 " ) | |
strequal ( servername , " ::1 " ) ) {
2007-10-11 05:25:16 +04:00
return true ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
if ( strequal ( servername , " localhost " ) ) {
2007-10-11 05:25:16 +04:00
return true ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* Maybe it's my dns name */
2007-11-09 04:25:45 +03:00
dnsname = get_mydnsfullname ( ) ;
if ( dnsname & & strequal ( servername , dnsname ) ) {
return true ;
2007-10-16 03:11:48 +04:00
}
2007-10-11 05:25:16 +04:00
2007-10-16 03:11:48 +04:00
/* Handle possible CNAME records - convert to an IP addr. */
if ( ! is_ipaddress ( servername ) ) {
/* Use DNS to resolve the name, but only the first address */
struct sockaddr_storage ss ;
if ( interpret_string_addr ( & ss , servername , 0 ) ) {
print_sockaddr ( name ,
sizeof ( name ) ,
2007-10-25 01:16:54 +04:00
& ss ) ;
2007-10-11 05:25:16 +04:00
servername = name ;
}
}
2007-10-16 03:11:48 +04:00
/* Maybe its an IP address? */
if ( is_ipaddress ( servername ) ) {
2007-10-11 05:25:16 +04:00
struct sockaddr_storage ss ;
2007-11-05 09:20:04 +03:00
struct iface_struct * nics ;
2007-10-11 05:25:16 +04:00
int i , n ;
2007-10-16 03:11:48 +04:00
if ( ! interpret_string_addr ( & ss , servername , AI_NUMERICHOST ) ) {
2007-10-11 05:25:16 +04:00
return false ;
}
2007-10-16 03:11:48 +04:00
if ( is_zero_addr ( & ss ) | | is_loopback_addr ( & ss ) ) {
return false ;
}
2007-10-11 05:25:16 +04:00
2007-11-09 04:25:45 +03:00
nics = TALLOC_ARRAY ( ctx , struct iface_struct ,
2007-11-05 09:20:04 +03:00
MAX_INTERFACES ) ;
if ( ! nics ) {
return false ;
}
2007-10-11 05:25:16 +04:00
n = get_interfaces ( nics , MAX_INTERFACES ) ;
for ( i = 0 ; i < n ; i + + ) {
if ( addr_equal ( & nics [ i ] . ip , & ss ) ) {
2007-11-05 09:20:04 +03:00
TALLOC_FREE ( nics ) ;
2007-10-11 05:25:16 +04:00
return true ;
}
}
2007-11-05 09:20:04 +03:00
TALLOC_FREE ( nics ) ;
2007-10-11 05:25:16 +04:00
}
2007-10-16 03:11:48 +04:00
/* No match */
2007-10-11 05:25:16 +04:00
return false ;
}