SMB traffic analyzer vfs module from Holger Hetterich <hhetter@novell.com>
authorHolger Hetterich <hhetter@novell.com>
Wed, 24 Sep 2008 23:01:00 +0000 (19:01 -0400)
committerJim McDonough <jmcd@samba.org>
Wed, 24 Sep 2008 23:16:57 +0000 (19:16 -0400)
Used to gather data to feed to a database for live and historical
analysis of usage per user, per share, etc.

Helper apps to read the data still to come.  This one still needs to be
made ipv6 enabled (connection is made to the helper app).

source3/Makefile.in
source3/configure.in
source3/modules/vfs_smb_traffic_analyzer.c [new file with mode: 0644]

index 9e0a1179f3ba76e36e64ab182cc7e83d49f24c68..e541fb32e174dd7b34c4dedcbbf08dbb75862598 100644 (file)
@@ -621,6 +621,7 @@ VFS_FILEID_OBJ = modules/vfs_fileid.o
 VFS_AIO_FORK_OBJ = modules/vfs_aio_fork.o
 VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
 VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o
+VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -2403,6 +2404,10 @@ bin/acl_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_ACL_XATTR_OBJ)
        @echo "Building plugin $@"
        @$(SHLD_MODULE) $(VFS_ACL_XATTR_OBJ)
 
+bin/smb_traffic_analyzer.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SMB_TRAFFIC_ANALYZER_OBJ)
+       @echo "Building plugin $@"
+       @$(SHLD_MODULE) $(VFS_SMB_TRAFFIC_ANALYZER_OBJ)
+
 bin/registry.@SHLIBEXT@: $(BINARY_PREREQS) libgpo/gpext/registry.o
        @echo "Building plugin $@"
        @$(SHLD_MODULE) libgpo/gpext/registry.o
index 63e17dc717ad02d8ba818c3044514fb587f2cc39..8332b1e34ada5fc8b628c9e6e3505bce3d9dd2bf 100644 (file)
@@ -407,7 +407,7 @@ dnl These have to be built static:
 default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsarpc rpc_samr rpc_winreg rpc_initshutdown rpc_dssetup rpc_wkssvc rpc_svcctl2 rpc_ntsvcs2 rpc_netlogon rpc_netdfs rpc_srvsvc rpc_spoolss rpc_eventlog2 auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin vfs_default nss_info_template"
 
 dnl These are preferably build shared, and static if dlopen() is not available
-default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_acl_xattr"
+default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_xattr_tdb vfs_streams_xattr vfs_acl_xattr vfs_smb_traffic_analyzer"
 
 if test "x$developer" = xyes; then
    default_static_modules="$default_static_modules rpc_rpcecho"
@@ -6116,7 +6116,7 @@ SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_notify_fam, \$(VFS_NOTIFY_FAM_OBJ), "bin/notify_fam.$SHLIBEXT", VFS)
 SMB_MODULE(vfs_acl_xattr, \$(VFS_ACL_XATTR_OBJ), "bin/acl_xattr.$SHLIBEXT", VFS)
-
+SMB_MODULE(vfs_smb_traffic_analyzer, \$(VFS_SMB_TRAFFIC_ANALYZER_OBJ), "bin/smb_traffic_analyzer.$SHLIBEXT", VFS)
 
 SMB_SUBSYSTEM(VFS,smbd/vfs.o)
 
diff --git a/source3/modules/vfs_smb_traffic_analyzer.c b/source3/modules/vfs_smb_traffic_analyzer.c
new file mode 100644 (file)
index 0000000..4faa041
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * 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"
+#include "safe_string.h"
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+
+/* abstraction for the send_over_network function */
+#define UNIX_DOMAIN_SOCKET 1
+#define INTERNET_SOCKET 0
+
+
+/* Prototypes */
+
+extern userdom_struct current_user_info;
+
+static int vfs_smb_traffic_analyzer_debug_level = DBGC_VFS;
+
+NTSTATUS init_samba_module(void);
+
+static ssize_t smb_traffic_analyzer_write(vfs_handle_struct *handle,
+               files_struct *fsp, const void *data, size_t n);
+
+static ssize_t smb_traffic_analyzer_read(vfs_handle_struct *handle,
+               files_struct *fsp, void *data, size_t n);
+
+static ssize_t smb_traffic_analyzer_pwrite(vfs_handle_struct *handle,
+               files_struct *fsp, const void *data, size_t n,
+               SMB_OFF_T offset);
+
+static ssize_t smb_traffic_analyzer_pread(vfs_handle_struct *handle,
+               files_struct *fsp, void *data, size_t n, SMB_OFF_T offset);
+
+
+/* VFS operations we use */
+
+static vfs_op_tuple smb_traffic_analyzer_tuples[] = {
+
+       {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 init_samba_module(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: Couldn't register custom"
+                        "debugging class!\n"));
+       } else {
+               DEBUG(3, ("smb_traffic_analyzer: Debug class number of"
+                       "'smb_traffic_analyzer': %d\n", \
+                       vfs_smb_traffic_analyzer_debug_level));
+       }
+
+       return ret;
+}
+
+/* create the timestamp in sqlite compatible format */
+static void get_timestamp( char *String )
+{
+       struct timeval tv;
+       struct timezone tz;
+       struct tm *tm;
+       int seconds;
+
+       gettimeofday(&tv, &tz);
+       tm=localtime(&tv.tv_sec);
+       seconds=(float) (tv.tv_usec / 1000);
+
+       fstr_sprintf(String,"%04d-%02d-%02d %02d:%02d:%02d.%03d", \
+                       tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, \
+                       tm->tm_hour, tm->tm_min, tm->tm_sec, (int)seconds);
+
+}
+
+static int smb_traffic_analyzer_connMode( vfs_handle_struct *handle)
+{
+       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;
+       }
+
+}
+
+
+
+/* Send data over a internet socket */
+static void smb_traffic_analyzer_send_data_inet_socket( char *String,
+                       vfs_handle_struct *handle, const char *file_name,
+                       bool Write)
+{
+        /* Create a streaming Socket */
+        const char *Hostname;
+        int sockfd, result;
+        int port;
+        struct sockaddr_in their_addr;
+       struct hostent *hp;
+        char Sender[200];
+        char TimeStamp[200];
+        int yes = 1;
+       connection_struct *conn;
+
+        if ((sockfd=socket(AF_INET, SOCK_STREAM,0)) == -1) {
+                DEBUG(1, ("unable to create socket, error is %s", 
+                         strerror(errno)));
+                return;
+        }
+        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, \
+                                                       sizeof(int)) == -1) {
+                DEBUG(1, ("unable to set socket options, error is %s", 
+                         strerror(errno)));
+                return;
+        }
+       /* get port number, target system from the config parameters */
+       conn=handle->conn;
+
+       Hostname=lp_parm_const_string(SNUM(conn), "smb_traffic_analyzer", 
+               "host", "localhost");
+
+       port = atoi( lp_parm_const_string(SNUM(conn), 
+                               "smb_traffic_analyzer", "port", "9430"));
+
+       hp = gethostbyname(Hostname);
+       if (hp == NULL) {
+               DEBUG(1, ("smb_traffic_analyzer: Unkown Hostname of"
+                       "target system!\n"));
+       }
+       DEBUG(3,("smb_traffic_analyzer: Internet socket mode. Hostname: %s,"
+               "Port: %i\n", Hostname, port));
+
+       their_addr.sin_family = AF_INET;
+        their_addr.sin_port = htons(port);
+        their_addr.sin_addr.s_addr = INADDR_ANY;
+        memset(their_addr.sin_zero, '\0', sizeof(their_addr.sin_zero));
+       memcpy(hp->h_addr, &their_addr.sin_addr, hp->h_length);
+       their_addr.sin_port=htons(port);
+       result=connect( sockfd, &their_addr, sizeof( struct sockaddr_in));
+       if ( result < 0 ) {
+               DEBUG(1, ("smb_traffic_analyzer: Couldn't connect to inet"
+                       "socket!\n"));
+       }
+        safe_strcpy(Sender, String, sizeof(Sender) - 1);
+        safe_strcat(Sender, ",\"", sizeof(Sender) - 1);
+        safe_strcat(Sender, get_current_username(), sizeof(Sender) - 1);
+        safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+        safe_strcat(Sender, current_user_info.domain, sizeof(Sender) - 1);
+        safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+        if (Write)
+               safe_strcat(Sender, "W", sizeof(Sender) - 1);
+       else
+               safe_strcat(Sender, "R", sizeof(Sender) - 1);
+        safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+        safe_strcat(Sender, handle->conn->connectpath, sizeof(Sender) - 1);
+        safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+        safe_strcat(Sender, file_name, sizeof(Sender) - 1);
+        safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+        get_timestamp(TimeStamp);
+        safe_strcat(Sender, TimeStamp, sizeof(Sender) - 1);
+        safe_strcat(Sender, "\");", sizeof(Sender) - 1);
+        DEBUG(10, ("smb_traffic_analyzer: sending %s\n", Sender));
+        if ( send(sockfd, Sender, strlen(Sender), 0) == -1 ) {
+                DEBUG(1, ("smb_traffic_analyzer: error sending data to socket!\n"));
+                return ;
+        }
+
+        /* one operation, close the socket */
+        close(sockfd);
+}
+
+
+
+/* Send data over a unix domain socket */
+static void smb_traffic_analyzer_send_data_unix_socket( char *String ,
+                       vfs_handle_struct *handle, const char *file_name, 
+                       bool Write)
+{
+       /* Create the socket to stad */
+       int len, sock;
+       struct sockaddr_un remote;
+        char Sender[200];
+        char TimeStamp[200];
+       DEBUG(7, ("smb_traffic_analyzer: Unix domain socket mode. Using "
+                       "/var/tmp/stadsocket\n"));
+       if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+               DEBUG(1, ("smb_traffic_analyzer: Couldn create socket,"
+                       "make sure stad is running!\n"));
+       }
+       remote.sun_family = AF_UNIX;
+       safe_strcpy(remote.sun_path, "/var/tmp/stadsocket", 
+                   sizeof(remote.sun_path) - 1);
+       len=strlen(remote.sun_path) + sizeof(remote.sun_family);
+       if (connect(sock, (struct sockaddr *)&remote, len) == -1 ) {
+               DEBUG(1, ("smb_traffic_analyzer: Could not connect to"
+                       "socket, make sure\nstad is running!\n"));
+       }
+       safe_strcpy(Sender, String, sizeof(Sender) - 1);
+       safe_strcat(Sender, ",\"", sizeof(Sender) - 1);
+       safe_strcat(Sender, get_current_username(), sizeof(Sender) - 1);
+       safe_strcat(Sender,"\",\"",sizeof(Sender) - 1);
+       safe_strcat(Sender, current_user_info.domain, sizeof(Sender) - 1);
+       safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+       if (Write)
+               safe_strcat(Sender, "W", sizeof(Sender) - 1);
+       else
+               safe_strcat(Sender, "R", sizeof(Sender) - 1);
+       safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+       safe_strcat(Sender, handle->conn->connectpath, sizeof(Sender) - 1);
+       safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+       safe_strcat(Sender, file_name, sizeof(Sender) - 1);
+       safe_strcat(Sender, "\",\"", sizeof(Sender) - 1);
+       get_timestamp(TimeStamp);
+       safe_strcat(Sender, TimeStamp, sizeof(Sender) - 1);
+       safe_strcat(Sender, "\");", sizeof(Sender) - 1);
+
+       DEBUG(10, ("smb_traffic_analyzer: sending %s\n", Sender));
+       if ( send(sock, Sender, strlen(Sender), 0) == -1 ) {
+               DEBUG(1, ("smb_traffic_analyzer: error sending data to"
+                       "socket!\n"));
+               return;
+       }
+
+       /* one operation, close the socket */
+       close(sock);
+
+       return;
+}
+
+static void smb_traffic_analyzer_send_data( char *Buffer , vfs_handle_struct \
+                       *handle, char *file_name, bool Write, files_struct *fsp)
+{
+
+        if (smb_traffic_analyzer_connMode(handle) == UNIX_DOMAIN_SOCKET) {
+                smb_traffic_analyzer_send_data_unix_socket(Buffer, handle, \
+                                                       fsp->fsp_name, Write);
+        } else {
+                smb_traffic_analyzer_send_data_inet_socket(Buffer, handle, \
+                                                       fsp->fsp_name, Write);
+        }
+}
+
+
+
+/* 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;
+        char Buffer[100];
+
+       result = SMB_VFS_NEXT_READ(handle, fsp, data, n);
+       DEBUG(10, ("smb_traffic_analyzer: READ: %s\n", fsp->fsp_name ));
+
+       fstr_sprintf(Buffer, "%u", (uint) result);
+
+       smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, false, fsp);
+       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;
+        char Buffer[100];
+
+       result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+
+       DEBUG(10, ("smb_traffic_analyzer: READ: %s\n", fsp->fsp_name ));
+
+       fstr_sprintf(Buffer,"%u", (uint) result);
+       smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, false, fsp);
+
+       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;
+        char Buffer[100];
+
+       result = SMB_VFS_NEXT_WRITE(handle, fsp, data, n);
+
+       DEBUG(10, ("smb_traffic_analyzer: WRITE: %s\n", fsp->fsp_name ));
+
+       fstr_sprintf(Buffer, "%u", (uint) result);
+       smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, \
+                                                               true, fsp );
+       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;
+        char Buffer[100];
+
+       result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+
+       DEBUG(10, ("smb_traffic_analyzer: PWRITE: %s\n", fsp->fsp_name ));
+
+       fstr_sprintf(Buffer, "%u", (uint) result);
+       smb_traffic_analyzer_send_data(Buffer, handle, fsp->fsp_name, true, fsp);
+       return result;
+}
+