Eida.cz - Firewallová krize, balancery a analýza Samby

Firewallová krize, balancery a analýza Samby

Eida

Je to už pár dní, bylo potřeba intenzivně dělat zas jiné věci kvůli výzkumu a tak. Přesto prolétlo během Vánoc a na přelomu roku kolem hlavy několik málo již nevyhnutelných postřehů, ulehčujících tu šílenou a sebezničující snahu zachovat všechno ještě v nějakém původním řádu. Jenomže všechno stejně spěje ke skáze.

Pamatuju se, jak 6n0m3 onehdáž ve svém asi třetím díle… nějakého asi howto o Linuxu - ono to totiž už bude skoro 15 let zpátky - zmiňoval v souvislosti s dial-upem, že Linux bez Internetu postrádá to kouzlo. A ono to platí dneska téměř pro všechno, protože bez připojení k Internetu slouží operační systémy pouze k práci a ještě často v nějakých dost specifických oblastech. Jinak jsou všichni permanentně připojení a píší sociální statůsky, nebo, v lepším případě, sledují lolcaty na redditu. Internet měl za úkol být svobodný, otevřený a servery veselé a zajímavé. Dneska už všechno postrádá kouzlo, ať už to připojené je, nebo není. 

V posledních letech přibylo hodně hloupých klientů a ještě víc hloupých serverových aplikací, o které je potřeba se sem tam starat a poskytovat je určitým skupinám více či méně hloupých uživatelů. Jenže během zimy (ale už i na podzim, na jaře a taky v průběhu léta) taky přichází období, kdy exponenciálně rostou zahraniční připojení a slovníkové útoky na různé služby. S trochou optimismu se asi dá tvrdit, že riziko reálného průniku na dobře udržovaný a aktualizovaný systém je mizivé, ale v okamžik, kdy požadavky vylezou do statisíců denně, se vše začne už dost negativně projevovat na infrastruktuře - servery jsou vyčerpané vypisováním odpovědí nějakým kujónům, o které tady nikdo nestojí.

To je firewallová krize, protože je velmi složité přesně říct, kdo může a kdo nemůže na poskytované služby. Pohled do logu ale dává určitou šanci, že ministerstvo obrany ČLR a různé jiné čínské agentury zřejmě nemají zájem o námi pečlivě připravovaná data a prostě jen zkoušejí, co se dá. Bylo by ale morální zablokovat Čínu? Po minutě přemýšlení byl udělen tichý souhlas. Původní idea vycházela z prostého blacklistu pro určitou zemi a nebyla v principu špatná, jenže to pořád nebylo úplně ono. Existuje na to taky poučka.

Dřív, když na vesnici přišli cikáni, zavíraly se slepice a pouštěli se psi. Když by přišli Číňani, děláte to naopak.

Geografická diskriminace probíhá všude na světě a opravdu neexistuje důvod, proč by jiné země (ba dokonce jiné kraje) měly mít přístup do našeho už tak málo čiperného a nevýkonného interního webového systému. Východiskem může být se uzavřít do sebe a znovu obnovit tu myšlenku výchozí politiky blokování a pouštět prostě jen někoho. Starali jsme se o internetovou svobodu tak dlouho, až se nám nakonec stala vězením.

Výsledek skutečně připomíná všechno, co se už osvědčilo začátkem století. Porty tady ale ošetřuje externí gateway, takže nemá smysl se jimi nějak významně zabývat - pokud přibude nějaká polovičatá služba, zahrne se sem speciálním záznamem.

iptables.conf 1.48 KiB
# iptables pro IPv4

*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

# chainy pro fail2ban
:fail2ban-ssh - [0:0]
:fail2ban-ssh-ddos - [0:0]

# chain pro whitelist
:whitelist - [0:0]

# lokalni smycka
-A INPUT -i lo -j ACCEPT
# fyzicka LAN
-A INPUT -s 10.10.10.0/24 -j ACCEPT

# primarni VPN
-A INPUT -s 10.8.8.0/24 -j ACCEPT
# herni VPN, nesmi na server
-A INPUT -s 10.100.100.0/24 -j DROP

# pripojeni na VPN zvenku
-A INPUT -p udp -m udp --dport 9874 -j ACCEPT
-A INPUT -p udp -m udp --dport 8765 -j ACCEPT

# 
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# jako kontrola pres whitelist
-A INPUT -j whitelist

# pravidla fail2ban
-A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh-ddos
-A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh

# povoleni verejnych sluzeb zde (ssh, http(s))
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

# navazana spojeni se preposilaji automaticky
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# z primarni VPN je povoleno pristupovat do fyzicke LAN
-A FORWARD -s 10.8.8.0/24 -d 10.10.10.0/24 -o eth0 -m conntrack --ctstate NEW -j ACCEPT

# fail2ban
-A fail2ban-ssh -j RETURN
-A fail2ban-ssh-ddos -j RETURN
COMMIT

# NAT pro VPN
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
# primarni VPN se v LAN maskuje adresou serveru
-A POSTROUTING -s 10.8.8.0/24 -o eth0 -j MASQUERADE
COMMIT
Omezená konfigurace iptables s whitelistem

Těžko říct, jak moc spolehlivě pracuje geoip plugin pro iptables a i kdyby dobře, byla by to zase zbytečná práce navíc. Z výše uvedeného nápadu na blacklist vznikl skript pro whitelist, kde naopak stačí zmínit povolené území a je vymalováno.

whitezone.sh 1.12 KiB
#!/bin/bash

# co povolit (mezerou oddelene ISO kody zemi)
ISO="cz"

# binarky Linuxu
IPT=/sbin/iptables
IPT6=/sbin/ip6tables
WGET=/usr/bin/wget

# nazev chainu v iptables (musi jiz existovat), zdroje, online zdroje
WHITELIST="whitelist"
# kde budou ulozeny zaznamy
ZONEROOT="/root/zonelist"
# rooty agregovanych adresnich bloku
DLROOT="http://www.ipdeny.com/ipblocks/data/aggregated"
DL6ROOT="http://www.ipdeny.com/ipv6/ipaddresses/aggregated"


# pro jistotu - vytvoreni adresare se zonami
[ ! -d $ZONEROOT ] && /bin/mkdir -p $ZONEROOT

# smazani starych zaznamu v chainu
$IPT -F $WHITELIST
$IPT6 -F $WHITELIST


# naplneni tabulek
for c in $ISO
do
	# lokalni databaze
	LDB=$ZONEROOT/$c.zone

	# stazeni zaznamu
	$WGET -O $LDB $DLROOT/$c\-aggregated.zone

	# seznam IPv4
	ALLOWIPS=$(egrep -v "^#|^$" $LDB)

	for ip in $ALLOWIPS
	do
		$IPT -A $WHITELIST -s $ip -j RETURN
	done
	
	$IPT -A $WHITELIST -j DROP

	# totez s IPv6
	ADB6=$ZONEROOT/$c.6.zone
	$WGET -O $ADB6 $DL6ROOT/$c\-aggregated.zone

	ALLOW6IPS=$(egrep -v "^#|^$" $ADB6)
	for ip6 in $ALLOW6IPS
	do
		$IPT6 -A $WHITELIST -s $ip6 -j RETURN
	done

	$IPT6 -A $WHITELIST -j DROP

done

Skript pro naplnění whitelistové chainu agregovanými CIDR záznamy z požadovaných zón

Pokud by zón bylo náhodou víc a existovala by reálná šance jejich překrývání, dá se ještě využít jednoduchý CIDR agregátor. IPv6 je sice daleko větší průser, ale konfigurace tam vypadá podobně. Fantasii se mozky do cesty nekladou.

Mimo jiné z toho taky vyplývá, že domácí a tyhle malopodnikové sítě už přestávají být vhodné pro provoz celosvětově dostupného webu. Naopak je to celkem užitečné pro omezení specifických aplikací, které by bylo dokonce až škodlivé poskytovat v zahraničí, když to má sloužit jen našim dětem. Ale to už jsme na tom opravdu tak bledě, když musíme poskytovat aplikaci dětem?

Práce se sítěmi a agregátorem v mnohém připomíná blokování facebooku pro pracovní stanice v učebně a určitě by se dala propagovat i na servery s Windows, jenže… jejich firewally nejsou úplně dobře stavěné na taková množství (natož správu) záznamů a navíc, co si budeme povídat, protože tam věčně něco nefunguje, tak jsou kolikrát nastaveny prostě nějak. A když už prostě ta pitomá .NET 4.0 aplikace musí běžet v nativní IIS a ne na mod_mono, minimálně by pomohlo, kdyby požadavky zvenku stejně obstarával Apache, jako reverzní proxy. Ono to navíc tomu zastaralému Windows 2003 vyloženě prospěje.

iis.conf 890 bajtů
<Virtualhost *:80>

	ServerName iis.eida.cz

	ProxyPreserveHost On
	ProxyRequests Off
	ProxyPass / http://10.0.0.5:80/ retry=1 acquire=3000 timeout=600 Keepalive=On
	ProxyPassReverse / http://10.0.0.5:80/

	Alias /peklo/ /dev/null

</Virtualhost>

<VirtualHost *:443>

	ServerName iis.eida.cz

	SSLEngine On
	SSLCertificateFile /etc/apache2/ssl/iis.pem
	SSLCertificateKeyFile /etc/apache2/ssl/iis.pem

	SSLProxyEngine On
	SSLProxyMachineCertificateChainFile /etc/apache2/ssl/iis.pem
	SSLProxyCACertificateFile /etc/apache2/ssl/ca.pem
	SSLProxyCheckPeerCN Off
	SSLProxyCheckPeerExpire On
	SSLProxyVerify none
	SSLProxyCheckPeerName off
	
	RequestHeader set Front-End-Https "On"

	ProxyPreserveHost On
	ProxyRequests Off
  	ProxyPass / https://10.0.0.5:443/ retry=1 acquire=3000 timeout=600 Keepalive=On
  	ProxyPassReverse / https://10.0.0.5:443/


  	Alias /peklo/ /dev/null

</VirtualHost>
Konfigurace reverzní proxy pro IIS server v LAN

Virtualhost tady používá mod_proxy pro přístup přes LAN na IIS server s aplikací a poskytuje ji přes sebe ven, a to včetně SSL. Tohle mimochodem umožňuje i celkem pěknou škálovatelnost a snadnou migraci jednoduchým přepisem, případně se dá ještě využít mod_proxy_balancer pro rozložení zátěže na víc serverů - a k tomu dojde, pokud dostaneme nějaké nové stroje, na kterých bude určitě Windows 2012 R2 nebo něco podobně ošklivého.

V rámci dolování dat mám na srdci ještě poslední postřeh, a to potíže při pokusu o analýzu Samby a jejího provozu. Docela slušná řádka věcí se v Sambě dá dělat na úrovni VFS, sledování provozu taky není úplnou výjimkou. Poskytuje ho projekt SMBTA, který má za cíl poskytnout krátkodobé vytížení serverů v síti. Sama o sobě to není špatná myšlenka, ale úplně se nehodí pro případ, kdy je jen jeden server se sharem pro jednoho uživatele a je potřeba využití sledovat dlouhodobě.

SMBTA na githubu je asi nejnovější a ke vší smůle už přes čtyři roky stará verze, v oficiálních repozitářích Jessie o tom bohužel není ani zmínka. Je psaná dost na míru SQLite, což je sice fajn pro krátkodobé přehledy, ale pro dlouhodobý sběr dat by se spíš hodilo využít MySQL, když už nám tu tak vesele běží, takže nastal čas pro menší úpravy.

Kromě přepisu konvencí a hacku s transakcemi pro MySQL chybí původní verzi podpora pro ukládání IP adres klientů, přičemž protokol V2 patřičného VFS modulu Samby posílání adres díky hotovému patchi zaručuje. Struktura byla tedy špinavě rozšířená o položku pro políčko s IP adresou, které by mělo následovat hned po časovém razítku. A funguje to - občas to sice spadne kvůli nějakému leaku, ale pokud to periodicky v cronu kontroluje nějaký číhač a případně to znovu nahazuje v interaktivním režimu (systemd má občas tendenci démona z ne úplně známých příčin zabíjet), v pohodě se to zase naváže na UNIX socket a zapisuje dál. Ostatně Samba stejně odmítá správně pracovat při nastavení komunikace přes TCP a když to běží na localhostu, stejně to není potřeba.

patch.diff 22.33 KiB
diff -Naur smbtad/dist/smbtad smbtad-up/dist/smbtad
--- smbtad/dist/smbtad	2015-02-05 18:22:54.213894990 +0100
+++ smbtad-up/dist/smbtad	2015-02-05 18:22:06.000000000 +0100
@@ -1,5 +1,6 @@
-#! /bin/sh
+#!/bin/bash
 # Copyright (c) 2010 Holger Hetterich
+# Debianized by Eida.cz 2015
 #
 # Based on the smb script by Lars Müller <lmuelle@suse.de>
 #
@@ -20,75 +21,89 @@
 #	You should have received a copy of the GNU General Public License
 #	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
+
+#!/bin/bash
+# /etc/init.d/smbtad
+# version 2015-02-05
+
 ### BEGIN INIT INFO
-# Provides:       smbtad
+# Provides:   smbtad
 # Required-Start: $network $syslog
-# Should-Start:   
 # Required-Stop:  $network $syslog
+# Should-Start:   
 # Should-Stop:    
 # Default-Start:  3 5
 # Default-Stop:   0 1 2 6
-# Short-Description: SMB Traffic Analyzer Daemon
-# Description:    SMB Traffic Analyzer Daemon
+# Short-Description:    SMB Traffic Analyzer Daemon
+# Description:   SMB Traffic Analyzer Daemon
 ### END INIT INFO
 
-SMBTAD_BIN="/usr/bin/smbtad"
+# config
+SMBTAD_BIN="$(which smbtad)"
 SMBTAD_CONF="/etc/smbtad.conf"
 
-. /etc/rc.status
-rc_reset
-
 # Check for missing binary
 if [ ! -x ${SMBTAD_BIN} ]; then
 	echo -n >&2 "SMB Traffic Analyzer daemon, ${SMBTAD_BIN} is not installed. "
-	rc_status -s
 	exit 5
 fi
 
 # be extra carefull cause connection fail if TMPDIR is not writeable
 export TMPDIR="/var/tmp"
 
+
+
+#Start-Stop 
 case "$1" in
-	start)
-		echo -n "Starting SMB Traffic Analyzer daemon "
-		if [ ! -f ${SMBTAD_CONF} ]; then
-			echo -n >&2 "smbtad configuration file, ${SMBTAD_CONF} does not exist. "
-			rc_status -s
-			exit 6
-		fi
-		checkproc ${SMBTAD_BIN}
-		case $? in
-			0) echo -n "- Warning: daemon already running. " ;;
-		esac
-		test -f /etc/sysconfig/language && \
-			. /etc/sysconfig/language
-		export LC_ALL="$RC_LC_ALL"
-		export LC_CTYPE="$RC_LC_CTYPE"
-		export LANG="$RC_LANG"
-		startproc ${SMBTAD_BIN} -c ${SMBTAD_CONF}
-		unset LC_ALL LC_CTYPE LANG
-		rc_status -v
-		;;
-	stop)
-		echo -n "Shutting down SMB Traffic Analyzer daemon "
-		checkproc ${SMBTAD_BIN} || \
-			echo -n " Warning: daemon not running. "
-		killproc -t 10 ${SMBTAD_BIN}
-		rc_status -v
-		;;
-	restart)
-		$0 stop
-		$0 start
-		rc_status
-		;;
-	status)
-		echo -n "Checking for Samba SMB daemon "
-		checkproc ${SMBTAD_BIN}
-		rc_status -v
-		;;
-	*)
-		echo "Usage: $0 {start|stop|status|restart}"
-		exit 1
-		;;
+  start)
+    echo -n "Starting SMB Traffic Analyzer daemon "
+    
+	if [ ! -f ${SMBTAD_CONF} ]; then
+		echo -n >&2 "smbtad configuration file, ${SMBTAD_CONF} does not exist. "
+		exit 6
+	fi
+	
+	if [ "$(pidof smbtad)” ] 
+	then
+  		echo "SMB Traffic Analyzer daemon is already running."
+	else
+  		$SMBTAD_BIN -c $SMBTAD_CONF
+	fi
+	exit 1
+		
+    ;;
+  stop)
+    
+    if [ "$(pidof smbtad)" ] 
+	then
+  		killall smbtad
+	else
+  		echo "SMB Traffic Analyzer daemon is not running"
+	fi
+
+    exit 1
+    ;;
+  restart)
+  	echo "Restarting SMB Traffic Analyzer daemon "
+    killall smbtad
+    $SMBTAD_BIN -c $SMBTAD_CONF
+    ;;
+  backup)
+    mc_backup
+    ;;
+  status)
+    if [ "$(pidof smbtad)" ] 
+	then
+  		echo "SMB Traffic Analyzer daemon is running"
+	else
+  		echo "SMB Traffic Analyzer daemon is not running"
+	fi
+    ;;
+
+  *)
+  echo "Usage: $0 {start|stop|status|restart}"
+  exit 1
+  ;;
 esac
-rc_exit
+
+exit 0
diff -Naur smbtad/include/cache.h smbtad-up/include/cache.h
--- smbtad/include/cache.h	2015-02-05 18:22:54.233894985 +0100
+++ smbtad-up/include/cache.h	2015-02-05 15:51:14.000000000 +0100
@@ -33,6 +33,7 @@
 
 	char *username;
 	char *domain;
+	char *clientip; // client IP
 	char *share;
 	char *timestamp;
 	char *usersid;
diff -Naur smbtad/include/monitor-list.h smbtad-up/include/monitor-list.h
--- smbtad/include/monitor-list.h	2015-02-05 18:22:54.233894985 +0100
+++ smbtad-up/include/monitor-list.h	2015-02-05 15:33:42.000000000 +0100
@@ -49,6 +49,7 @@
 	char *share;
 	char *file;
 	char *domain;
+	char *clientip; /* client IP aaddress */
 
 	/* to be casted to a specific structure */
 	void *local_data;
@@ -93,8 +94,10 @@
         char *username,
         char *usersid,
         char *share,
-	char *file,
-        char *domain, unsigned long int data, char *montimestamp);
+	    char *file,
+        char *domain,
+        char *clientip,
+        unsigned long int data, char *montimestamp);
 
 int monitor_list_delete_by_socket( int sock );
 void monitor_list_set_init_result(char *res, int monitorid);
diff -Naur smbtad/include/protocol.h smbtad-up/include/protocol.h
--- smbtad/include/protocol.h	2015-02-05 18:22:54.233894985 +0100
+++ smbtad-up/include/protocol.h	2015-02-05 15:36:50.000000000 +0100
@@ -22,7 +22,7 @@
 #include <talloc.h>
 
 #define PROTOCOL_SUBRELEASE 0
-#define SMBTAD_COMMON_DATA_BLOCKS 6
+#define SMBTAD_COMMON_DATA_BLOCKS 7 // 6 + IP
 
 
 enum header_states {
diff -Naur smbtad/include/vfs_smb_traffic_analyzer.h smbtad-up/include/vfs_smb_traffic_analyzer.h
--- smbtad/include/vfs_smb_traffic_analyzer.h	2015-02-05 18:22:54.237894985 +0100
+++ smbtad-up/include/vfs_smb_traffic_analyzer.h	2015-02-05 16:00:56.000000000 +0100
@@ -77,7 +77,7 @@
  */
 
 /* Protocol subrelease number */
-#define SMBTA_SUBRELEASE 0
+#define SMBTA_SUBRELEASE '0'
 
 /*
  * Every data block sends a number of blocks sending common data
@@ -85,7 +85,7 @@
  * so that if the receiver is using an older version of the protocol
  * it knows which blocks it can ignore.
  */
-#define SMBTA_COMMON_DATA_COUNT "00016"
+#define SMBTA_COMMON_DATA_COUNT "00017"
 
 /*
  * VFS Functions identifier table. In protocol version 2, every vfs
diff -Naur smbtad/src/cache.c smbtad-up/src/cache.c
--- smbtad/src/cache.c	2015-02-05 18:22:54.241894983 +0100
+++ smbtad-up/src/cache.c	2015-02-05 17:31:50.000000000 +0100
@@ -111,7 +111,9 @@
 					&& strncmp(entry->username,
 						gotr->username, strlen(entry->username)) == 0
 					&& strncmp(entry->domain,
-						gotr->domain, strlen(entry->domain)) == 0) {
+						gotr->domain, strlen(entry->domain)) == 0
+					&& strncmp(entry->clientip,
+						gotr->clientip, strlen(entry->clientip)) == 0) {
 					/*
 				 	 * entry fits, add the value
 				 	 */
@@ -209,6 +211,7 @@
 		entry->share,
 		entry->filename,
 		entry->domain,
+		entry->clientip,
 		entry->len,
 		entry->timestamp);
 }
@@ -227,6 +230,7 @@
 	entry->share = NULL;
 	entry->filename = NULL;
 	entry->domain = NULL;
+	entry->clientip = NULL;
 	entry->len = 0;
 	entry->timestamp = NULL;
 
@@ -264,6 +268,8 @@
         entry->domain = protocol_get_single_data_block( data, &go_through );
         /* timestamp */
         entry->timestamp = protocol_get_single_data_block( data, &go_through );
+        /* clientip */
+        entry->clientip = protocol_get_single_data_block( data, &go_through );
 	
 	/**
 	 * In case the protocol transfers more common data blocks
@@ -271,7 +277,7 @@
 	 * happened in the Samba master and 3.6.0 branch as we have
 	 * added support for the IP address of the client to the protocol
 	 */
-	for ( t=0; t < common_blocks_num-6; t++) {
+	for ( t=0; t < common_blocks_num-7; t++) {
 		dummy = protocol_get_single_data_block( data, &go_through);
 		if (dummy == NULL) {
 			syslog(LOG_DEBUG,"Fatal: Expected more common data but\n"
@@ -341,6 +347,7 @@
 	char *username;
 	char *share;
 	char *domain;
+	char *clientip;
 	char *timestamp;
 	char *usersid;
 	/* fn depending strings */
@@ -349,6 +356,7 @@
 	dbi_conn_quote_string_copy( conf->DBIconn, entry->username, &username);
 	dbi_conn_quote_string_copy( conf->DBIconn, entry->share, &share);
 	dbi_conn_quote_string_copy( conf->DBIconn, entry->domain, &domain);
+	dbi_conn_quote_string_copy( conf->DBIconn, entry->clientip, &clientip);
 	dbi_conn_quote_string_copy( conf->DBIconn, entry->timestamp, ×tamp);
 	dbi_conn_quote_string_copy( conf->DBIconn, entry->usersid, &usersid);
 	switch( entry->op_id ) {
@@ -361,11 +369,11 @@
 				&result);
 
                 retstr = talloc_asprintf(ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, string2, result) VALUES ("
-                        "%i, %s,%s,%s,%s,"
+                        "%i, %s,%s,%s,%s,%s,"
                         "%s,%s,%s,%s);",
-                        entry->op_id,username,usersid,share,domain,timestamp,
+                        entry->op_id,username,usersid,share,domain,timestamp,clientip,
                         source,destination,result);
 		free(source);
 		free(destination);
@@ -376,11 +384,11 @@
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->result, &result);
 
                 retstr = talloc_asprintf(ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, result) VALUES ("
-                        "%i,%s,%s,%s,%s,"
+                        "%i,%s,%s,%s,%s,%s,"
                         "%s,%s,%s);",
-                        entry->op_id,username,usersid,share,domain,timestamp,
+                        entry->op_id,username,usersid,share,domain,timestamp,clientip,
                         filename,result);
 		free(result);
 		free(filename);
@@ -390,11 +398,11 @@
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->mode, &mode);
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->result, &result);
                 retstr = talloc_asprintf(ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, string2, result) VALUES ("
-                        "%i,%s,%s,%s,%s,"
+                        "%i,%s,%s,%s,%s,%s,"
                         "%s,%s,%s,%s);",
-                        entry->op_id,username,usersid,share,domain,timestamp,
+                        entry->op_id,username,usersid,share,domain,timestamp,clientip,
                         filename,mode,result);
 		free(mode);
 		free(result);
@@ -405,11 +413,11 @@
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->path, &path);
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->result, &result);
                 retstr = talloc_asprintf( ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, result) VALUES ("
-                        "%i,%s,%s,%s,%s,"
+                        "%i,%s,%s,%s,%s,%s,"
                         "%s,%s,%s);",
-                        entry->op_id,username,usersid,share,domain,timestamp,
+                        entry->op_id,username,usersid,share,domain,timestamp,clientip,
                         path,result);
 		free(path);
 		free(result);
@@ -419,11 +427,11 @@
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->mode, &mode);
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->result, &result);
                 retstr = talloc_asprintf(ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, string2, result) VALUES ("
-                        "%i,%s,%s,%s,%s,"
+                        "%i,%s,%s,%s,%s,%s,"
                         "%s,%s,%s,%s);",
-                        entry->op_id,username,usersid,share,domain,timestamp,
+                        entry->op_id,username,usersid,share,domain,timestamp,clientip,
                         path, mode, result);
 		free(mode);
 		free(result);
@@ -437,11 +445,11 @@
                 }
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->filename, &filename);
                 retstr = talloc_asprintf(ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, length) VALUES ("
-                        "%i,%s,%s,%s,%s,%s,"
+                        "%i,%s,%s,%s,%s,%s,%s,"
                         "%s,%lu);",
-                        vfs_id_write,username,usersid,share,domain,timestamp,
+                        vfs_id_write,username,usersid,share,domain,timestamp,clientip,
                         filename,entry->len);
 		free(filename);
                 break;	
@@ -453,11 +461,11 @@
                 }
 		dbi_conn_quote_string_copy( conf->DBIconn, entry->filename, &filename);
                 retstr = talloc_asprintf(ctx, "INSERT INTO data ("
-                        "vfs_id, username, usersid, share, domain, timestamp,"
+                        "vfs_id, username, usersid, share, domain, timestamp, clientip,"
                         "string1, length) VALUES ("
-                        "%i,%s,%s,%s,%s,%s,"
+                        "%i,%s,%s,%s,%s,%s,%s,"
                         "%s,%lu);",
-                        vfs_id_read,username,usersid,share,domain,timestamp,
+                        vfs_id_read,username,usersid,share,domain,timestamp,clientip,
                         filename,entry->len);
 		free(filename);
                 break;
@@ -468,6 +476,7 @@
 	free(share);
 	free(domain);
 	free(timestamp);
+	free(clientip);
 	free(usersid);
 	return retstr;
 }
@@ -488,7 +497,7 @@
 	 * Check if the connection is alive. We try ten times
 	 * to restore the connection if not
 	 */
-	for (try = 0; try < 10; try++) {
+	for (try = 0; try < 5; try++) {
 		rc = dbi_conn_ping( config->DBIconn );
 		if (rc == 1) {
 			result = dbi_conn_query(config->DBIconn, dbstring);
@@ -506,7 +515,7 @@
 	dbi_result_free(result);
 }
 
-void cleanup_cache( TALLOC_CTX *ctx,struct configuration_data *config,
+void cleanup_cache(TALLOC_CTX *ctx,struct configuration_data *config,
 	struct cache_entry *entry)
 {
 	char *dbstring;
@@ -604,9 +613,9 @@
 		pthread_mutex_unlock(&cache_mutex);
 		if (backup != NULL) {
 			/* store all existing entries into the database */
-			do_db(config,"BEGIN TRANSACTION;");
-			cleanup_cache( dbpool,config,backup);
-			do_db(config,"COMMIT;");
+			//do_db(config,"START TRANSACTION;");
+			cleanup_cache(dbpool, config, backup);
+			//do_db(config,"COMMIT;");
 		}
 		talloc_free(dbpool);
 
@@ -614,7 +623,7 @@
 			char String[400];
 			char dbstring[300];
 			struct tm *tm;
-			do_db(config,"BEGIN TRANSACTION;");
+			//do_db(config,"START TRANSACTION;");
 		        time_t today=time(NULL);
 		        time_t delete_date=today - config->maint_run_time;
 		        tm = localtime ( &delete_date );
@@ -625,11 +634,11 @@
                			tm->tm_hour, tm->tm_min, tm->tm_sec);
 
 
-       			strcpy(dbstring,"delete from data where timestamp < '");
+       			strcpy(dbstring,"DELETE FROM data WHERE timestamp < '");
        			strcat(dbstring,String);
        			strcat(dbstring,"';");
 			do_db(config,dbstring);
-			do_db(config,"COMMIT;");
+			//do_db(config,"COMMIT;");
 			maintenance_count = 0;
 		}
 				
diff -Naur smbtad/src/database.c smbtad-up/src/database.c
--- smbtad/src/database.c	2015-02-05 18:22:54.241894983 +0100
+++ smbtad-up/src/database.c	2015-02-05 15:26:37.000000000 +0100
@@ -20,7 +20,7 @@
  */
 
 #include "../include/includes.h"
-#define CREATE_COMMONS "vfs_id integer,username varchar,usersid varchar,share varchar,domain varchar,timestamp timestamp,"
+#define CREATE_COMMONS "vfs_id int,username varchar(255),usersid varchar(255),share varchar(255),domain varchar(255),timestamp datetime,clientip varchar(128),"
 int database_create_tables( struct configuration_data *conf );
 
 
@@ -198,7 +198,7 @@
 	result = dbi_conn_query( conf->DBIconn,
 		"CREATE TABLE data ("
 		 CREATE_COMMONS
-		"string1 varchar, length integer, result bigint, string2 varchar)");
+		"string1 varchar(255), length int, result bigint, string2 varchar(255))");
 	if (result == NULL) {
 		syslog(LOG_DEBUG,"create tables : could not create"
 			"the data table!");
@@ -211,23 +211,23 @@
 	 */
 	result = dbi_conn_query( conf->DBIconn,
 		"CREATE TABLE status ("
-		"smbtad_control_entry varchar,"
-		"smbtad_version varchar,"
-		"smbtad_database_version varchar,"
-		"smbtad_client_port integer,"
-		"smbtad_unix_socket_clients integer,"
-		"smbtad_dbname varchar,"
-		"smbtad_dbhost varchar,"
-		"smbtad_dbuser varchar,"
-		"smbtad_dbdriver varchar,"
-		"smbtad_maintenance_timer_str varchar,"
-		"smbtad_maintenance_run_time integer,"
-		"smbtad_debug_level integer,"
-		"smbtad_precision integer,"
-		"smbtad_daemon integer,"
-		"smbtad_use_db integer,"
-		"smbtad_config_file varchar,"
-		"smbtad_ip varchar);");
+		"smbtad_control_entry varchar(255),"
+		"smbtad_version varchar(255),"
+		"smbtad_database_version varchar(255),"
+		"smbtad_client_port int,"
+		"smbtad_unix_socket_clients int,"
+		"smbtad_dbname varchar(255),"
+		"smbtad_dbhost varchar(255),"
+		"smbtad_dbuser varchar(255),"
+		"smbtad_dbdriver varchar(255),"
+		"smbtad_maintenance_timer_str varchar(255),"
+		"smbtad_maintenance_run_time int,"
+		"smbtad_debug_level int,"
+		"smbtad_precision int,"
+		"smbtad_daemon int,"
+		"smbtad_use_db int,"
+		"smbtad_config_file varchar(255),"
+		"smbtad_ip varchar(255));");
 	if (result == NULL) {
 		syslog(LOG_DEBUG,"create tables: could not create"
 			"the status table!");
@@ -260,9 +260,9 @@
 	 */
 	result = dbi_conn_query( conf->DBIconn,
 		"CREATE TABLE modules ("
-		"module_subrelease_number integer,"
-		"module_common_blocks_overflow integer,"
-		"module_ip_address varchar UNIQUE);");
+		"module_subrelease_number int,"
+		"module_common_blocks_overflow int,"
+		"module_ip_address varchar(255) UNIQUE);");
 	if (result == NULL) {
 		syslog(LOG_DEBUG,"create tables: could not create"
 			"the modules table!");
diff -Naur smbtad/src/monitor-list.c smbtad-up/src/monitor-list.c
--- smbtad/src/monitor-list.c	2015-02-05 18:22:54.241894983 +0100
+++ smbtad-up/src/monitor-list.c	2015-02-05 15:39:29.000000000 +0100
@@ -36,7 +36,7 @@
  * adds an entry to the monitor list
  * returns -1 in case of an error
  */
-int monitor_list_add( char *data,int sock) {
+int monitor_list_add(char *data, int sock) {
         struct monitor_item *entry;
 	DEBUG(1) syslog(LOG_DEBUG,"Adding monitor Item %s ",data);
         if (monlist_start == NULL) {
@@ -62,6 +62,7 @@
 		entry->function = 255;
 		entry->share = NULL;
 		entry->domain = NULL;
+		entry->clientip = NULL; // client IP
 		entry->local_data = NULL;
 		monitor_id ++;
 		entry->state = MONITOR_IDENTIFY;
@@ -85,6 +86,7 @@
         entry->function = 255;
         entry->share = NULL;
         entry->domain = NULL;
+        entry->clientip = NULL;
 
 	monitor_id++;
 	entry->state = MONITOR_IDENTIFY;
@@ -202,9 +204,11 @@
 		monitor_list_parse_argument( entry->data, &c);
 	entry->domain =
 		monitor_list_parse_argument( entry->data, &c);
+	entry->clientip =
+		monitor_list_parse_argument( entry->data, &c);
 	DEBUG(8) syslog(LOG_DEBUG,"monitor_list_parse: parsed "
 		"id %i, function = %i, param = %s, username = %s,"
-		"usersid = %s, share = %s, file = %s, domain = %s",
+		"usersid = %s, share = %s, file = %s, domain = %s, clientip = %s",
 		entry->id,
 		entry->function,
 		entry->param,
@@ -212,7 +216,8 @@
 		entry->usersid,
 		entry->share,
 		entry->file,
-		entry->domain);
+		entry->domain,
+		entry->clientip);
 
 	/*
 	 * initialize a memory block with the specific local data
@@ -282,7 +287,8 @@
 	char *usersid,
 	char *share,
 	char *file,
-	char *domain)
+	char *domain,
+	char *clientip)
 {
 
         DEBUG(8) syslog(LOG_DEBUG, "monitor_list_apply: entry data:"
@@ -290,18 +296,20 @@
                 "entry->usersid  : |%s|vs|%s|, "
                 "entry->share    : %s, "
 		"entry->file	 : %s, "
-                "entry->domain   : %s. ",
+		        "entry->domain   : %s, "
+                "entry->clientip : %s. ",
                 entry->username,
 		username,
 		entry->usersid, 
 		usersid,
 		entry->share,
 		entry->file,
-		entry->domain);
+		entry->domain,
+		entry->clientip);
 
 	if (entry->username == NULL || entry->usersid == NULL
 		|| entry->share == NULL || entry->file == NULL
-		|| entry->domain == NULL) return 0;
+		|| entry->domain == NULL || entry->clientip == NULL) return 0;
 
 	if (strcmp(entry->username,"*") != 0) {
 		if (strcmp(entry->username, username)!=0) return 0;
@@ -318,6 +326,9 @@
 	if (strcmp(entry->domain,"*") != 0) {
 		if (strcmp(entry->domain, domain)!=0) return 0;
 	}
+	if (strcmp(entry->clientip,"*") != 0) {
+		if (strcmp(entry->clientip, clientip)!=0) return 0;
+	}
 	DEBUG(8) syslog(LOG_DEBUG, "monitor_list_apply: "
 		"monitor applied succesfully.");
 	return 1;
@@ -422,7 +433,10 @@
 	char *usersid,
 	char *share,
 	char *file,
-	char *domain, unsigned long int data, char *montimestamp)
+	char *domain,
+	char *clientip,
+	unsigned long int data,
+	char *montimestamp)
 {
 	char *fname;
 	struct monitor_item *entry = monlist_start;
@@ -433,7 +447,8 @@
 			usersid,
 			share,
 			file,
-			domain) == 1) {
+			domain,
+			clientip) == 1) {
 			/* processing monitor */
 			switch(entry->function) {
 			case MONITOR_ADD: ;
@@ -476,12 +491,14 @@
 				 */
 				if (file == NULL) fname=talloc_asprintf(NULL," ");
 				else fname = file;
-				char *tres = talloc_asprintf(op_id_str,"%04i%s" // op id
-                                	"%04i%s" // username
+				char *tres = talloc_asprintf(op_id_str,
+				    "%04i%s" // op id
+                    "%04i%s" // username
 					"%04i%s" // share
 					"%04i%s" // filename
 					"%04i%s" // domain
-					"%04i%s", // timestamp
+					"%04i%s" // timestamp
+					"%04i%s", // client IP
 					(int) strlen(op_id_str),
 					op_id_str,
 					(int) strlen(username),
@@ -493,7 +510,9 @@
 					(int) strlen(domain),
 					domain,
 					(int) strlen(montimestamp),
-					montimestamp);
+					montimestamp,
+					(int) strlen(clientip),
+					clientip);
 				if (file == NULL) talloc_free(fname);
 				if (tres == NULL) { // could'nd allocate
 						talloc_free(op_id_str);
diff -Naur smbtad/src/temp.c smbtad-up/src/temp.c
--- smbtad/src/temp.c	2015-02-05 18:22:54.241894983 +0100
+++ smbtad-up/src/temp.c	2015-02-05 15:51:41.000000000 +0100
@@ -30,6 +30,8 @@
         cache_en->domain = protocol_get_single_data_block( go_through );
         /* timestamp */
         cache_en->timestamp = protocol_get_single_data_block( go_through );
+        /* clientip */
+		cache_en->clientip = protocol_get_single_data_block( go_through );
 
         /* now check if there are more common data blocks to come */
         /* we will ignore them, if we don't handle more common data */
Souhrn provedených změn v SMBTAd

Kompletní zdrojový kód upraveného SMBTA. Natvrdo používá MySQL a zapisuje IP adresu klienta.

Za pár hodin běhu to umí vygenerovat ohromné množství dat, takže po měsíci dostane MySQL teprve pořádně zabrat při zpracování. Zápis bez mazání je potřeba ošetřit v konfiguraci SMBTA, protože se s takovým používáním úplně nepočítá.

smbtad.conf 663 bajtů
[general]
        debug_level = 0
        # databaze
        use_db = 1

[network]
        # pokud by to melo bezet na siti, ale neni to potreba	
        smbtad_ip = localhost
        query_port = 3491

        # pro jeden server je ale snazsi pouzit UNIX sockety
        unix_domain_socket = yes
        unix_domain_socket_clients = no

[database]
        # pouzije se MySQL
        driver = mysql
        host = localhost        
        name = smbta
        user = smbta
        password = smbanalyzerpwd

[maintenance]
        # jednou za 20 hodin to zkontroluje, jestli tam je vic jak 365 dni dat :D
        interval = 20:00:00
        config = 365,00:00:00
Konfigurace démona SMBTA

Samozřejmě nic z těchto postřehů a pokusů není ideální a šlo by to udělat určitě milionkrát líp, jenže všechno jde vždycky udělat milionkrát líp, pokud je k tomu důvod. A když není, tak se to prostě udělá jen tak, aby to splnilo svůj účel, nebo aby to bylo v rámci možností ještě zábavné. Sice už nic nebude takové, jako to bylo za úsvitu Internetu, ale zcela jistě přijdou příležitosti udělat technologii takovou, jaká nebyla ještě nikdy předtím.

Tento článek přečetlo již 488 čtenářů (0 dnes).

Komentáře

Nový komentář