2008-09-25 03:01:00 +04:00
/*
* traffic - analyzer VFS module . Measure the smb traffic users create
* on the net .
*
* Copyright ( C ) Holger Hetterich , 2008
2008-10-01 23:50:29 +04:00
* Copyright ( C ) Jeremy Allison , 2008
2008-09-25 03:01:00 +04: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
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
/* abstraction for the send_over_network function */
2008-10-01 23:50:29 +04:00
enum sock_type { INTERNET_SOCKET = 0 , UNIX_DOMAIN_SOCKET } ;
# define LOCAL_PATHNAME " / var / tmp / stadsocket"
2008-09-25 03:01:00 +04:00
static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS ;
2008-10-01 23:50:29 +04:00
static enum sock_type smb_traffic_analyzer_connMode ( vfs_handle_struct * handle )
2008-09-25 03:01:00 +04:00
{
connection_struct * conn = handle - > conn ;
const char * Mode ;
Mode = lp_parm_const_string ( SNUM ( conn ) , " smb_traffic_analyzer " , " mode " , \
" internet_socket " ) ;
if ( strstr ( Mode , " unix_domain_socket " ) ) {
return UNIX_DOMAIN_SOCKET ;
} else {
return INTERNET_SOCKET ;
}
}
2008-10-14 01:08:49 +04:00
2008-10-01 02:13:19 +04:00
/* Connect to an internet socket */
2008-10-01 23:50:29 +04:00
static int smb_traffic_analyzer_connect_inet_socket ( vfs_handle_struct * handle ,
const char * name , uint16_t port )
2008-09-25 03:01:00 +04:00
{
2008-09-25 23:02:22 +04:00
/* Create a streaming Socket */
int sockfd = - 1 ;
struct addrinfo hints ;
struct addrinfo * ailist = NULL ;
struct addrinfo * res = NULL ;
int ret ;
2008-09-25 03:01:00 +04:00
2008-09-25 23:02:22 +04:00
ZERO_STRUCT ( hints ) ;
/* By default make sure it supports TCP. */
hints . ai_socktype = SOCK_STREAM ;
hints . ai_flags = AI_ADDRCONFIG ;
2008-10-01 23:50:29 +04:00
ret = getaddrinfo ( name ,
2008-09-25 23:02:22 +04:00
NULL ,
& hints ,
& ailist ) ;
if ( ret ) {
2008-10-01 02:13:19 +04:00
DEBUG ( 3 , ( " smb_traffic_analyzer_connect_inet_socket: "
2008-09-25 23:02:22 +04:00
" getaddrinfo failed for name %s [%s] \n " ,
2008-10-01 23:50:29 +04:00
name ,
2008-09-25 23:02:22 +04:00
gai_strerror ( ret ) ) ) ;
2008-10-01 02:13:19 +04:00
return - 1 ;
2008-09-25 23:02:22 +04:00
}
2008-09-25 03:01:00 +04:00
DEBUG ( 3 , ( " smb_traffic_analyzer: Internet socket mode. Hostname: %s, "
2008-10-01 23:50:29 +04:00
" Port: %i \n " , name , port ) ) ;
2008-09-25 03:01:00 +04:00
2008-09-25 23:02:22 +04:00
for ( res = ailist ; res ; res = res - > ai_next ) {
struct sockaddr_storage ss ;
2009-01-03 21:50:05 +03:00
NTSTATUS status ;
2008-09-25 23:02:22 +04:00
if ( ! res - > ai_addr | | res - > ai_addrlen = = 0 ) {
continue ;
}
ZERO_STRUCT ( ss ) ;
memcpy ( & ss , res - > ai_addr , res - > ai_addrlen ) ;
2009-01-03 21:50:05 +03:00
status = open_socket_out ( & ss , port , 10000 , & sockfd ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2008-09-25 23:02:22 +04:00
break ;
}
}
if ( ailist ) {
freeaddrinfo ( ailist ) ;
}
if ( sockfd = = - 1 ) {
2008-10-01 02:13:19 +04:00
DEBUG ( 1 , ( " smb_traffic_analyzer: unable to create "
" socket, error is %s " ,
2008-09-25 23:02:22 +04:00
strerror ( errno ) ) ) ;
2008-10-01 02:13:19 +04:00
return - 1 ;
2008-09-25 03:01:00 +04:00
}
2008-09-25 23:02:22 +04:00
2008-10-01 02:13:19 +04:00
return sockfd ;
2008-09-25 03:01:00 +04:00
}
2008-10-01 02:13:19 +04:00
/* Connect to a unix domain socket */
2008-09-25 03:01:00 +04:00
2008-10-01 23:50:29 +04:00
static int smb_traffic_analyzer_connect_unix_socket ( vfs_handle_struct * handle ,
const char * name )
2008-09-25 03:01:00 +04:00
{
/* Create the socket to stad */
int len , sock ;
struct sockaddr_un remote ;
2008-09-25 23:02:22 +04:00
2008-10-01 02:13:19 +04:00
DEBUG ( 7 , ( " smb_traffic_analyzer_connect_unix_socket: "
2008-10-01 23:50:29 +04:00
" Unix domain socket mode. Using %s \n " ,
name ) ) ;
2008-09-25 23:02:22 +04:00
2008-09-25 03:01:00 +04:00
if ( ( sock = socket ( AF_UNIX , SOCK_STREAM , 0 ) ) = = - 1 ) {
2008-10-01 02:13:19 +04:00
DEBUG ( 1 , ( " smb_traffic_analyzer_connect_unix_socket: "
" Couldn't create socket, "
2008-09-25 03:01:00 +04:00
" make sure stad is running! \n " ) ) ;
2008-10-30 02:43:19 +03:00
return - 1 ;
2008-09-25 03:01:00 +04:00
}
remote . sun_family = AF_UNIX ;
2008-10-01 23:50:29 +04:00
strlcpy ( remote . sun_path , name ,
2008-09-25 23:02:22 +04:00
sizeof ( remote . sun_path ) ) ;
2008-09-25 03:01:00 +04:00
len = strlen ( remote . sun_path ) + sizeof ( remote . sun_family ) ;
if ( connect ( sock , ( struct sockaddr * ) & remote , len ) = = - 1 ) {
2008-10-01 02:13:19 +04:00
DEBUG ( 1 , ( " smb_traffic_analyzer_connect_unix_socket: "
" Could not connect to "
2008-09-25 03:01:00 +04:00
" socket, make sure \n stad is running! \n " ) ) ;
2008-09-25 23:02:22 +04:00
close ( sock ) ;
2008-10-01 02:13:19 +04:00
return - 1 ;
}
return sock ;
}
2008-10-01 23:50:29 +04:00
/* Private data allowing shared connection sockets. */
struct refcounted_sock {
struct refcounted_sock * next , * prev ;
char * name ;
uint16_t port ;
int sock ;
unsigned int ref_count ;
} ;
2008-10-01 02:13:19 +04:00
/* Send data over a socket */
static void smb_traffic_analyzer_send_data ( vfs_handle_struct * handle ,
2008-10-01 03:19:37 +04:00
ssize_t result ,
2008-10-01 02:13:19 +04:00
const char * file_name ,
bool Write )
{
2008-10-01 23:50:29 +04:00
struct refcounted_sock * rf_sock = NULL ;
2008-10-01 03:19:37 +04:00
struct timeval tv ;
2008-10-07 04:09:48 +04:00
time_t tv_sec ;
2008-10-01 03:19:37 +04:00
struct tm * tm = NULL ;
int seconds ;
char * str = NULL ;
2008-10-14 01:08:49 +04:00
char * username = NULL ;
const char * anon_prefix = NULL ;
2009-02-04 17:31:24 +03:00
const char * total_anonymization = NULL ;
2008-10-01 03:19:37 +04:00
size_t len ;
2008-10-01 02:13:19 +04:00
2008-10-01 23:50:29 +04:00
SMB_VFS_HANDLE_GET_DATA ( handle , rf_sock , struct refcounted_sock , return ) ;
2008-10-01 02:13:19 +04:00
2008-10-01 23:50:29 +04:00
if ( rf_sock = = NULL | | rf_sock - > sock = = - 1 ) {
2008-10-01 02:13:19 +04:00
DEBUG ( 1 , ( " smb_traffic_analyzer_send_data: socket is "
" closed \n " ) ) ;
2008-09-25 23:02:22 +04:00
return ;
2008-09-25 03:01:00 +04:00
}
2008-10-01 02:13:19 +04:00
2008-10-01 03:19:37 +04:00
GetTimeOfDay ( & tv ) ;
2008-10-07 04:09:48 +04:00
tv_sec = convert_timespec_to_time_t ( convert_timeval_to_timespec ( tv ) ) ;
tm = localtime ( & tv_sec ) ;
2008-10-01 03:19:37 +04:00
if ( ! tm ) {
return ;
}
seconds = ( float ) ( tv . tv_usec / 1000 ) ;
2008-10-14 01:08:49 +04:00
/* check if anonymization is required */
2008-10-14 01:12:43 +04:00
2009-02-04 17:31:24 +03:00
total_anonymization = lp_parm_const_string ( SNUM ( handle - > conn ) , " smb_traffic_analyzer " ,
" total_anonymization " , NULL ) ;
2008-10-14 01:08:49 +04:00
anon_prefix = lp_parm_const_string ( SNUM ( handle - > conn ) , " smb_traffic_analyzer " , \
" anonymize_prefix " , NULL ) ;
if ( anon_prefix ! = NULL ) {
2009-02-04 17:31:24 +03:00
if ( total_anonymization ! = NULL ) {
username = talloc_asprintf ( talloc_tos ( ) ,
" %s " ,
anon_prefix ) ;
} else {
username = talloc_asprintf ( talloc_tos ( ) ,
" %s%i " ,
anon_prefix ,
str_checksum (
handle - > conn - > server_info - > sanitized_username ) ) ;
}
2008-10-14 01:08:49 +04:00
} else {
2008-10-14 01:12:43 +04:00
username = handle - > conn - > server_info - > sanitized_username ;
}
2008-10-14 01:08:49 +04:00
if ( ! username ) {
return ;
2008-10-14 01:12:43 +04:00
}
2008-10-14 01:08:49 +04:00
2008-10-01 03:19:37 +04:00
str = talloc_asprintf ( talloc_tos ( ) ,
2008-10-01 23:50:29 +04:00
" V1,%u, \" %s \" , \" %s \" , \" %c \" , \" %s \" , \" %s \" , "
" \" %04d-%02d-%02d %02d:%02d:%02d.%03d \" \n " ,
2008-10-01 03:19:37 +04:00
( unsigned int ) result ,
2008-10-14 01:08:49 +04:00
username ,
2008-10-01 03:19:37 +04:00
pdb_get_domain ( handle - > conn - > server_info - > sam_account ) ,
Write ? ' W ' : ' R ' ,
handle - > conn - > connectpath ,
file_name ,
tm - > tm_year + 1900 ,
tm - > tm_mon + 1 ,
tm - > tm_mday ,
tm - > tm_hour ,
tm - > tm_min ,
tm - > tm_sec ,
( int ) seconds ) ;
if ( ! str ) {
return ;
}
len = strlen ( str ) ;
2008-10-01 02:13:19 +04:00
DEBUG ( 10 , ( " smb_traffic_analyzer_send_data_socket: sending %s \n " ,
2008-10-01 03:19:37 +04:00
str ) ) ;
2008-10-01 23:50:29 +04:00
if ( write_data ( rf_sock - > sock , str , len ) ! = len ) {
2008-10-01 02:13:19 +04:00
DEBUG ( 1 , ( " smb_traffic_analyzer_send_data_socket: "
" error sending data to socket! \n " ) ) ;
return ;
2008-09-25 03:01:00 +04:00
}
2008-10-01 02:13:19 +04:00
}
2008-09-25 03:01:00 +04:00
2008-10-01 23:50:29 +04:00
static struct refcounted_sock * sock_list ;
2008-10-01 02:13:19 +04:00
static void smb_traffic_analyzer_free_data ( void * * pptr )
{
2008-10-01 23:50:29 +04:00
struct refcounted_sock * rf_sock = * ( struct refcounted_sock * * ) pptr ;
if ( rf_sock = = NULL ) {
2008-10-01 02:13:19 +04:00
return ;
}
2008-10-01 23:50:29 +04:00
rf_sock - > ref_count - - ;
if ( rf_sock - > ref_count ! = 0 ) {
return ;
}
if ( rf_sock - > sock ! = - 1 ) {
close ( rf_sock - > sock ) ;
2008-10-01 02:13:19 +04:00
}
2008-10-01 23:50:29 +04:00
DLIST_REMOVE ( sock_list , rf_sock ) ;
TALLOC_FREE ( rf_sock ) ;
2008-09-25 03:01:00 +04:00
}
2008-10-01 02:13:19 +04:00
static int smb_traffic_analyzer_connect ( struct vfs_handle_struct * handle ,
const char * service ,
const char * user )
2008-09-25 03:01:00 +04:00
{
2008-10-01 23:50:29 +04:00
connection_struct * conn = handle - > conn ;
enum sock_type st = smb_traffic_analyzer_connMode ( handle ) ;
struct refcounted_sock * rf_sock = NULL ;
const char * name = ( st = = UNIX_DOMAIN_SOCKET ) ? LOCAL_PATHNAME :
lp_parm_const_string ( SNUM ( conn ) ,
" smb_traffic_analyzer " ,
" host " , " localhost " ) ;
uint16_t port = ( st = = UNIX_DOMAIN_SOCKET ) ? 0 :
atoi ( lp_parm_const_string ( SNUM ( conn ) ,
" smb_traffic_analyzer " , " port " , " 9430 " ) ) ;
2008-09-25 03:01:00 +04:00
2008-10-01 23:50:29 +04:00
/* Are we already connected ? */
for ( rf_sock = sock_list ; rf_sock ; rf_sock = rf_sock - > next ) {
if ( port = = rf_sock - > port & &
( strcmp ( name , rf_sock - > name ) = = 0 ) ) {
break ;
}
2008-10-01 02:13:19 +04:00
}
2008-09-25 03:01:00 +04:00
2008-10-01 23:50:29 +04:00
/* If we're connected already, just increase the
* reference count . */
if ( rf_sock ) {
rf_sock - > ref_count + + ;
2008-10-01 02:13:19 +04:00
} else {
2008-10-01 23:50:29 +04:00
/* New connection. */
rf_sock = TALLOC_ZERO_P ( NULL , struct refcounted_sock ) ;
if ( rf_sock = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
rf_sock - > name = talloc_strdup ( rf_sock , name ) ;
if ( rf_sock - > name = = NULL ) {
TALLOC_FREE ( rf_sock ) ;
errno = ENOMEM ;
return - 1 ;
}
rf_sock - > port = port ;
rf_sock - > ref_count = 1 ;
if ( st = = UNIX_DOMAIN_SOCKET ) {
rf_sock - > sock = smb_traffic_analyzer_connect_unix_socket ( handle ,
name ) ;
} else {
rf_sock - > sock = smb_traffic_analyzer_connect_inet_socket ( handle ,
name ,
port ) ;
}
if ( rf_sock - > sock = = - 1 ) {
TALLOC_FREE ( rf_sock ) ;
return - 1 ;
}
DLIST_ADD ( sock_list , rf_sock ) ;
2008-10-01 02:13:19 +04:00
}
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
/* Store the private data. */
2008-10-01 23:50:29 +04:00
SMB_VFS_HANDLE_SET_DATA ( handle , rf_sock , smb_traffic_analyzer_free_data ,
struct refcounted_sock , return - 1 ) ;
2008-10-01 02:13:19 +04:00
return SMB_VFS_NEXT_CONNECT ( handle , service , user ) ;
}
2008-09-25 03:01:00 +04:00
/* VFS Functions: write, read, pread, pwrite for now */
static ssize_t smb_traffic_analyzer_read ( vfs_handle_struct * handle , \
files_struct * fsp , void * data , size_t n )
{
ssize_t result ;
result = SMB_VFS_NEXT_READ ( handle , fsp , data , n ) ;
2008-10-01 02:13:19 +04:00
DEBUG ( 10 , ( " smb_traffic_analyzer_read: READ: %s \n " , fsp - > fsp_name ) ) ;
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
smb_traffic_analyzer_send_data ( handle ,
2008-10-01 03:19:37 +04:00
result ,
2008-10-01 02:13:19 +04:00
fsp - > fsp_name ,
false ) ;
2008-09-25 03:01:00 +04:00
return result ;
}
static ssize_t smb_traffic_analyzer_pread ( vfs_handle_struct * handle , \
files_struct * fsp , void * data , size_t n , SMB_OFF_T offset )
{
ssize_t result ;
result = SMB_VFS_NEXT_PREAD ( handle , fsp , data , n , offset ) ;
2008-10-01 02:13:19 +04:00
DEBUG ( 10 , ( " smb_traffic_analyzer_pread: PREAD: %s \n " , fsp - > fsp_name ) ) ;
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
smb_traffic_analyzer_send_data ( handle ,
2008-10-01 03:19:37 +04:00
result ,
2008-10-01 02:13:19 +04:00
fsp - > fsp_name ,
false ) ;
2008-09-25 03:01:00 +04:00
return result ;
}
static ssize_t smb_traffic_analyzer_write ( vfs_handle_struct * handle , \
files_struct * fsp , const void * data , size_t n )
{
ssize_t result ;
result = SMB_VFS_NEXT_WRITE ( handle , fsp , data , n ) ;
2008-10-01 02:13:19 +04:00
DEBUG ( 10 , ( " smb_traffic_analyzer_write: WRITE: %s \n " , fsp - > fsp_name ) ) ;
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
smb_traffic_analyzer_send_data ( handle ,
2008-10-01 03:19:37 +04:00
result ,
2008-10-01 02:13:19 +04:00
fsp - > fsp_name ,
true ) ;
2008-09-25 03:01:00 +04:00
return result ;
}
static ssize_t smb_traffic_analyzer_pwrite ( vfs_handle_struct * handle , \
files_struct * fsp , const void * data , size_t n , SMB_OFF_T offset )
{
ssize_t result ;
result = SMB_VFS_NEXT_PWRITE ( handle , fsp , data , n , offset ) ;
2008-10-01 02:13:19 +04:00
DEBUG ( 10 , ( " smb_traffic_analyzer_pwrite: PWRITE: %s \n " , fsp - > fsp_name ) ) ;
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
smb_traffic_analyzer_send_data ( handle ,
2008-10-01 03:19:37 +04:00
result ,
2008-10-01 02:13:19 +04:00
fsp - > fsp_name ,
true ) ;
2008-09-25 03:01:00 +04:00
return result ;
}
2008-10-01 02:13:19 +04:00
/* VFS operations we use */
static vfs_op_tuple smb_traffic_analyzer_tuples [ ] = {
{ SMB_VFS_OP ( smb_traffic_analyzer_connect ) , SMB_VFS_OP_CONNECT ,
SMB_VFS_LAYER_LOGGER } ,
{ SMB_VFS_OP ( smb_traffic_analyzer_read ) , SMB_VFS_OP_READ ,
SMB_VFS_LAYER_LOGGER } ,
{ SMB_VFS_OP ( smb_traffic_analyzer_pread ) , SMB_VFS_OP_PREAD ,
SMB_VFS_LAYER_LOGGER } ,
{ SMB_VFS_OP ( smb_traffic_analyzer_write ) , SMB_VFS_OP_WRITE ,
SMB_VFS_LAYER_LOGGER } ,
{ SMB_VFS_OP ( smb_traffic_analyzer_pwrite ) , SMB_VFS_OP_PWRITE ,
SMB_VFS_LAYER_LOGGER } ,
{ SMB_VFS_OP ( NULL ) , SMB_VFS_OP_NOOP , SMB_VFS_LAYER_NOOP }
} ;
/* Module initialization */
NTSTATUS vfs_smb_traffic_analyzer_init ( void )
{
NTSTATUS ret = smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , \
" smb_traffic_analyzer " , smb_traffic_analyzer_tuples ) ;
if ( ! NT_STATUS_IS_OK ( ret ) ) {
return ret ;
}
vfs_smb_traffic_analyzer_debug_level =
debug_add_class ( " smb_traffic_analyzer " ) ;
if ( vfs_smb_traffic_analyzer_debug_level = = - 1 ) {
vfs_smb_traffic_analyzer_debug_level = DBGC_VFS ;
DEBUG ( 1 , ( " smb_traffic_analyzer_init: Couldn't register custom "
" debugging class! \n " ) ) ;
} else {
DEBUG ( 3 , ( " smb_traffic_analyzer_init: Debug class number of "
" 'smb_traffic_analyzer': %d \n " , \
vfs_smb_traffic_analyzer_debug_level ) ) ;
}
return ret ;
}