rendez-vous sur ArraKISS
Archives ContactATOM
whoami@ybad.name
# find . -iname

    Statistiques pour spamd - WIP

    J’en ai parlé plusieurs fois ici, j’adore spamd pour embêter les spammeurs.

    Je voulais depuis longtemps obtenir des statistiques afin de mieux suivre l’évolution des pièges. À ce jour, j’ai un truc qui fonctionne : spamdcharts.

    J’utilise chart.js pour générer les graphiques. Ça me plait moyennement, l’idéal serait de tout tracer en SVG.

    Sinon, le code est très (mais alors très) vilain : c’est du shell, c’est très lent… Toutefois, ça fait le job.

    Puisque c’est “WIP” (en cours), j’envisage de :

    Je pose le code ici, mais je rappelle qu’il est tout sale :

    #!/bin/sh
    # Author: prx <prx@ybad.name>
    # licence: MIT
    # Description : Generate charts about spamd(8) traps
    
    set -e
    
    # defaults
    data=/var/spamdcharts_data 
    log=/var/log/daemon
    title="spamd traps stats"
    
    # vars
    fpfile=${data}/.footprint
    
    # functions
    help() {
    	printf "%s\n" "usage: $0 > charts.html
    	  [ -d directory where data is stored (default: ./spamdcharts_data) ]
    	  [ -l spamd logs files (default: /var/log/daemon*) ]
    	  [ -s relative path to stylesheet ]
    	  [ -t title ]
    	  [ -h help ]"
    
    	exit
    }
    rand() {
    	printf "%s" "$(jot -r 1 $1 $2)"
    }
    randcol() {
    	printf "%s\n" "rgba($(rand 0 255),$(rand 0 255),$(rand 0 255), 0.3)"
    }
    monthtonum() {
    	num=""
    	case $1 in
    		"Jan") num="01" ;;
    		"Feb") num="02" ;;
    		"Mar") num="03" ;;
    		"Apr") num="04" ;;
    		"May") num="05" ;;
    		"Jun") num="06" ;;
    		"Jul") num="07" ;;
    		"Aug") num="08" ;;
    		"Sep") num="09" ;;
    		"Oct") num="10" ;;
    		"Nov") num="11" ;;
    		"Dec") num="12" ;;
    	esac
    	printf "%s" "${num}"
    }
    
    # parse options, override defaults
    while getopts d:l:s:t:h o; do
    	case "${o}" in
    		d ) data="${OPTARG}" ;;
    		l ) log="${OPTARG}" ;;
    		s ) stylesheet="${OPTARG}" ;;
    		t ) title="${OPTARG}" ;;
    		h ) help ;;
    	esac
    done
    
    logtodata() {
    	# parse log and store data
    	mkdir -p "${data}"
    	y=$(date +%Y) # assume year is now
    	month=""
    	sec=""
    	day=""
    	list=""
    
    	# last log seen at this date : month-day-time (whithout -)
    	test -f "${fpfile}" && fp="$(cat ${fpfile})" || fp=0
    		
    	(gzcat ${log}*.gz; cat "${log}") |\
    		grep "spamd.*disconnected.*lists:" |\
    		tr -s " " |\
    		cut -d' ' -f 1,2,3,9,12 |\
    		while read -r month day t sec list; do
    			month="$(monthtonum ${month})"
    			day="$(printf "%02d" ${day})"
    
    			t=$(printf "%s" "${t}" | tr -d ':')
    			newfp="${y}${month}${day}${t}"
    
    			# if line older than last run, do nothing
    			test ${newfp} -gt ${fp} || continue
    
    			fp=${newfp}
    			printf "%s" "${newfp}" > "${fpfile}"
    
    			dir="${data}/${y}/${month}/${day}"
    			listfile="${dir}/${list}"
    
    			mkdir -p "${dir}"
    			# get last record if any and store sum of time wasted
    			test -f "${listfile}" && sec=$((${sec} + $(cat "${listfile}")))
    			printf "%s" "${sec}" > "${listfile}"
    	done 
    }
    
    gencharts() {
    	# this is crappy...
    labels=""
    points=""
    
    cat << EOF
    <!doctype html>
    <html>
    <head>
    <title>${title}</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" 
    	href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.css">
    <link rel="stylesheet" type="text/css" 
    	href="${stylesheet}" >
    </head>
    <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
    <h1>${title}</h1>
    <p>Last update : $(date +%F-%X)</p>
    EOF
    
    
    for year in $(ls ${data}); do
    	test -d "${data}/${year}" || continue
    	# line chart over year
    cat << EOF
    <h2>${year}</h2>
    <h3>Spammers time wasted in ${year}</h3>
    <div class="spamdchart">
    	<canvas id="${year}linechart">
    		<p>Spammers time wasted in ${year} thanks to spamd</p>
    	</canvas>
    </div>
    <script>
    var ctx = document.getElementById("${year}linechart");
    var myChart = new Chart(ctx, {
    	type: "line",
    	data: {
    EOF
    	for month in $(ls "${data}/${year}"); do
    		for day in $(ls "${data}/${year}/${month}"); do
    			labels="${labels}\"${month}-${day}\","
    			n=0
    			for l in ${data}/${year}/${month}/${day}/* ; do
    				n=$((${n}+$(cat ${l})))
    			done
    			points="${points} ${n},"
    		done
    	done
    cat << EOF 
    	labels: [${labels}],
    		datasets: [{
    			label: 'trap duration (s)',
    			data: [ ${points} ]
    		}]
    	}
    });
    </script>
    EOF
    
    	cat << EOF
    <h3>Total time wasted per blacklist</h3>
    <div class="spamdchart">
    	<canvas id="${year}piechart">
    		<p>Spammers time wasted pie chart in ${year} thanks to spamd</p>
    	</canvas>
    </div>
    <script>
    var ctx = document.getElementById("${year}piechart");
    var myChart = new Chart(ctx, {
    	type: "pie",
    	data: {
    EOF
    			
    	labels=""
    	points=""
    	colors=""
    	lists="$(find ${data} -type f ! -name ".*" |\
    				awk -F'/' '{print $NF}' |\
    		sort -u)"
    
    	for l in ${lists}; do
    		labels="${labels} \"${l}\","
    		colors="${colors} \"$(randcol)\","
    		n=0
    		for s in $(find ${data} -type f -name "${l}"); do
    			n=$((${n} + $(cat ${s})))
    		done
    		points="${points}${n},"
    	done
    
    cat << EOF
    	datasets: [{
    		data: [ ${points} ],
    		backgroundColor: [ ${colors} ],
    	}],
    	labels: [ ${labels} ],
    },
    	options: {
    		responsive:true,
    	}
    });
    </script>
    EOF
    
    done
    
    printf "%s\n" "</body></html>"
    }
    
    logtodata
    gencharts