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
*
* 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 */
# define UNIX_DOMAIN_SOCKET 1
# define INTERNET_SOCKET 0
static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS ;
2008-10-01 02:13:19 +04:00
static int 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-01 02:13:19 +04:00
/* Connect to an internet socket */
static int smb_traffic_analyzer_connect_inet_socket ( vfs_handle_struct * handle )
2008-09-25 03:01:00 +04:00
{
2008-09-25 23:02:22 +04:00
/* Create a streaming Socket */
const char * Hostname ;
int sockfd = - 1 ;
uint16_t port ;
struct addrinfo hints ;
struct addrinfo * ailist = NULL ;
struct addrinfo * res = NULL ;
connection_struct * conn = handle - > conn ;
int ret ;
2008-09-25 03:01:00 +04:00
/* get port number, target system from the config parameters */
2008-10-01 02:13:19 +04:00
Hostname = lp_parm_const_string ( SNUM ( conn ) , " smb_traffic_analyzer " ,
2008-09-25 23:02:22 +04:00
" host " , " localhost " ) ;
ZERO_STRUCT ( hints ) ;
/* By default make sure it supports TCP. */
hints . ai_socktype = SOCK_STREAM ;
hints . ai_flags = AI_ADDRCONFIG ;
ret = getaddrinfo ( Hostname ,
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 " ,
Hostname ,
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
2008-10-01 02:13:19 +04:00
port = atoi ( lp_parm_const_string ( SNUM ( conn ) ,
2008-09-25 03:01:00 +04:00
" smb_traffic_analyzer " , " port " , " 9430 " ) ) ;
DEBUG ( 3 , ( " smb_traffic_analyzer: Internet socket mode. Hostname: %s, "
" Port: %i \n " , Hostname , port ) ) ;
2008-09-25 23:02:22 +04:00
for ( res = ailist ; res ; res = res - > ai_next ) {
struct sockaddr_storage ss ;
if ( ! res - > ai_addr | | res - > ai_addrlen = = 0 ) {
continue ;
}
ZERO_STRUCT ( ss ) ;
memcpy ( & ss , res - > ai_addr , res - > ai_addrlen ) ;
sockfd = open_socket_out ( SOCK_STREAM , & ss , port , 10000 ) ;
if ( sockfd ! = - 1 ) {
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 02:13:19 +04:00
static int smb_traffic_analyzer_connect_unix_socket ( vfs_handle_struct * handle )
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: "
" Unix domain socket mode. Using "
2008-09-25 03:01:00 +04:00
" /var/tmp/stadsocket \n " ) ) ;
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 " ) ) ;
}
remote . sun_family = AF_UNIX ;
2008-10-01 02:13:19 +04:00
strlcpy ( remote . sun_path , " /var/tmp/stadsocket " ,
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 ;
}
/* 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 )
{
int * psockfd = NULL ;
2008-10-01 03:19:37 +04:00
struct timeval tv ;
struct tm * tm = NULL ;
int seconds ;
char * str = NULL ;
size_t len ;
2008-10-01 02:13:19 +04:00
SMB_VFS_HANDLE_GET_DATA ( handle , psockfd , int , return ) ;
if ( psockfd = = NULL | | * psockfd = = - 1 ) {
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 ) ;
tm = localtime ( & tv . tv_sec ) ;
if ( ! tm ) {
return ;
}
seconds = ( float ) ( tv . tv_usec / 1000 ) ;
str = talloc_asprintf ( talloc_tos ( ) ,
" %u, \" %s \" , \" %s \" , \" %c \" , \" %s \" , \" %s \" , "
" \" %04d-%02d-%02d %02d:%02d:%02d.%03d \" ); " ,
( unsigned int ) result ,
handle - > conn - > server_info - > sanitized_username ,
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 ) ) ;
if ( write_data ( * psockfd , 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 02:13:19 +04:00
static void smb_traffic_analyzer_free_data ( void * * pptr )
{
int * pfd = * ( int * * ) pptr ;
if ( ! pfd ) {
return ;
}
if ( * pfd ! = - 1 ) {
close ( * pfd ) ;
}
TALLOC_FREE ( pfd ) ;
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 02:13:19 +04:00
int * pfd = TALLOC_P ( handle , int ) ;
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
if ( ! pfd ) {
errno = ENOMEM ;
return - 1 ;
}
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
if ( smb_traffic_analyzer_connMode ( handle ) = = UNIX_DOMAIN_SOCKET ) {
* pfd = smb_traffic_analyzer_connect_unix_socket ( handle ) ;
} else {
* pfd = smb_traffic_analyzer_connect_inet_socket ( handle ) ;
}
if ( * pfd = = - 1 ) {
return - 1 ;
}
2008-09-25 03:01:00 +04:00
2008-10-01 02:13:19 +04:00
/* Store the private data. */
SMB_VFS_HANDLE_SET_DATA ( handle , pfd , smb_traffic_analyzer_free_data ,
int , return - 1 ) ;
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 ;
}