Script zum Setzen der Linux Timezone

Es gibt dafür durchaus Pakete und Binaries, die das übernehmen, aber warum nicht selbst machen und ein wenig mit select spielen?

#!/bin/bash
# Simple script to set system TZ for any linux system
echo "Setting the TZ of this system:"
if [ "$EUID" -ne 0 ]; then
  echo "Please run as root"
  exit
fi
cd /usr/share/zoneinfo/posix
PS3="Select the Region: "
select WREG in $(find . -type d | sed "s/\.\///g" | fgrep -v ".") other; do
	if [ -z $WREG ]; then
		echo "Not changing TZ"
		break
	fi
	echo "Selected the Region: $WREG "
	PS3="Select the TZ: "
	if [ $WREG == "other" ]; then
		mapfile -t WREGLIST < <( find . -maxdepth 1 -not -type d | sed "s/\.\///g" )
		WREG=""
	else
		cd $WREG
		mapfile -t WREGLIST < <( find . -not -type d | sed "s/\.\///g" )
	fi
	select WREGTZ in ${WREGLIST[*]}; do
		if [ -z $WREGTZ ]; then
			echo "Not changing TZ"
		break
		fi
	echo "Selected the TZ: $WREGTZ "
	ln -s /usr/share/zoneinfo/$WREG/$WREGTZ /etc/localtime
	echo "Current date is: $(date)"
	break
	done
break
done
Script zum Setzen der Linux Timezone

Aus CIDR-Schreibweise eine Maske berechnen

Es gibt Python-Scripte dafür und Perl-Bibliotheken auch, aber was, wenn man in Bash eine IPv4-Prefixlänge in eine Maske umrechnen will? Etwa /24 in 255.255.255.0? Das geht so:

#!/bin/bash

function PFLcalc () {
        let NN=32-$1
        PL=$(printf -- '1%.0s' $(seq 1 $1))
        PR=$(printf -- '0%.0s' $(seq 1 $NN))
        PF=$PL$PR
        OCT1=$(echo "ibase=2; ${PF:0:8}" | bc)
        OCT2=$(echo "ibase=2; ${PF:8:8}" | bc)
        OCT3=$(echo "ibase=2; ${PF:16:8}" | bc)
        OCT4=$(echo "ibase=2; ${PF:24:8}" | bc)
        MASK=$OCT1.$OCT2.$OCT3.$OCT4
}
PFLcalc $1 # call script with int le 24
echo "Mask is $MASK"

Ja, bei einer Länge von 0 verrechnet sich das Script. Pech.

Aus CIDR-Schreibweise eine Maske berechnen

Böse bleiben draußen

Mein Server ist genervt. Ständig probieren irgend welche Bots aus, Passworte zu erraten und scannen Ports ab. Daher habe ich fail2ban installiert, das notorische Passwort-Ausprobierer ausbremst. Es gibt aber auch Betreiber von Honeypot-Netzwerken, die besonders aggresive IPs sammeln und diese in Listen zur Verfügung stellen. Ich habe mir eine solche Liste von einem Czechischen Anbieter herausgesucht und in einen iptables Filter umgewandelt. Und das geht so:

#!/bin/bash

BLKSRC="https://security.etnetera.cz/feeds/etn_aggressive.txt"
CHAIN="aggressiveips"
IPTBIN="/sbin/iptables"
TDAY=$(date +%d)
YDAY=$(date +%d --date="-1 day")
ADMIN="admin@internet.tld"

# create new chain for today
$IPTBIN -N $CHAIN$TDAY
# insert all IPs from the source into the chain (this takes a while)
for BIP in $(curl $BLKSRC 2>/dev/null | egrep -v "^#|^$|\:"); do
$IPTBIN -A $CHAIN$TDAY -s $BIP -j LOG --log-prefix "[netfilter] $CHAIN$TDAY "
$IPTBIN -A $CHAIN$TDAY -s $BIP -j DROP
done
# add a RETURN policy to allow other chains to be examined
$IPTBIN -A $CHAIN$TDAY -j RETURN
# insert chain into the INPUT chain
$IPTBIN -A INPUT  -j $CHAIN$TDAY
# delete yesterdays chain from INPUT chain
$IPTBIN -D INPUT -j $CHAIN$YDAY
$IPTBIN -F $CHAIN$YDAY
$IPTBIN -X $CHAIN$YDAY
# report
BLKCNT=$($IPTBIN -n -L $CHAIN$TDAY | fgrep DROP | wc -l)
echo "Installed $BLKCNT blocked IPs from $CHAIN - $BLKSRC on $(date)" | mail -s "$CHAIN result" $ADMIN

Das Script lädt als cronjob, der ein Mal nächtlich läuft, die aktuelle Liste herunter, sortiert alle Leerzeilen und Kommentarzeilen sowie IPv6-Adressen (egrep den Doppelpunkt) aus und installiert dann eine iptables chain. Ich nutze den heutigen und gestrigen Tag als Teil der chain, damit beim Neuladen nicht während der Installation der chain der Server von nervenden Anfragen gekitzelt wird.

Und damit ich einfacher für jeden Tag eine Auswertung machen kann. Und da kommt eine ganze Menge zusammen. Das aber ander mal.

Böse bleiben draußen

Abgelaufene SSL Zertifikate

Es ist mir leider mehr als nur ein mal passiert, dass der Mailserver mit abgelaufenen SSL-Zertifikaten lief. Bei Let’s Encrypt laufen diese Zertifikate ja relativ schnell (3 Monate) ab. Daher brauche ich eine Warnung, falls das passiert und der automatische Restart nicht geklappt hat.

Man kann natürlich die Cert Dateien im Filesystem prüfen, aber viel besser ist doch den Dienst direkt zu fragen. Und das geht so (und das kann auch remote laufen):

#!/bin/bash

# SMTPS Host to check
HOST=my.mailserver.tld
# Days before end of cert to warn/take action
WARNDAYS=14
# admin email
CONTACT="adminofmymailserver@gmail.com"

ENDDATE=$(echo QUIT | openssl s_client -connect $HOST:465 -verify_return_error 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'| openssl x509 -noout -dates  | fgrep notAfter | sed 's/notAfter=//g')
# echo $ENDDATE cert expires
EPOCHENDDATE=$(date --date="$ENDDATE" +"%s")
# echo epoch is $EPOCHENDDATE
EPOCHTODAY=$(date +"%s")
let TIMELEFT=$EPOCHENDDATE-$EPOCHTODAY
DAYSLEFT=$(echo "$TIMELEFT/86400" | bc)
# echo time left $DAYSLEFT days
if [ $DAYSLEFT -le $WARNDAYS ]; then
  echo "WARNING: Cert for $HOST expires in $DAYSLEFT days!" | mail -s "WARNING: Cert for $HOST expires in $DAYSLEFT days!" $CONTACT
  # /etc/init.d/exim4 restart
fi

Die Herausforderung ist, das Ablaufdatum im Zertifikat in Tage gerechnet von Heute umzuwandeln. Das geht mit dem Befehl „date“, der in epoch umwandelt und einer einfachen Division ohne Rest durch 86400 (Sekunden pro Tag) der Differenz mit „bc“.

Abgelaufene SSL Zertifikate

Time Machine like backups

If you backup your data to a remote server or a local disk with a script (I strongly recommend rsync to do so, otherwise this script will most probably not work), you should also keep old versions of that data to be able to rollback to an earlier version. But if you have a LOT of data, your HD will run full. So better just keep the deltas.

In my case its half a terabyte of email data from a mail server. Many files change every day. Get deleted, added, moved.
To keep old versions (you could call them snapshots) of the backups, I use hardlinks, that will just create a new link to an existing file in the filesystem. It is not a symbolic link, meaning the actual file will only get deleted, when the last hardlink will be deleted from the filesystem. In my case, this will happen 10 days after the original file was deleted.

#!/bin/bash

BASEDIR="/var/bkp/" # base directory
BDIR=mybackup # directory to backup
DAYS=10
cp -al $BASEDIR/$BDIR/ $BASEDIR/$BDIR$(date +%Y%m%d)
if [ -d $BASEDIR/$BDIR$(date +%Y%m%d --date="-$DAYS day") ]; then
 echo "deleting old backup $BDIR$(date +%Y%m%d --date="-$DAYS day")..."
 rm -rf $BASEDIR/$BDIR$(date +%Y%m%d --date="-$DAYS day")
else
 echo -n "No old backups at "
 date +%Y%m%d --date="-$DAYS day"
fi
Time Machine like backups

Bandbreite anzeigen

Die aktuell genutzte Bandbreite eines Linux Systems wird ermittelt als übertragene Bytes pro Zeitabstand. Einen „aktuellen“ Wert zum Auslesen gibt es nicht, man muss also die Bandbreite aus zwei Deltawerten übertragener Bytes berechnen. Ich habe ein Script gefunden und etwas erweitert. Es zeigt die Bandbreite für alle Interfaces in Kbits und Mbits an. Das Script ist simpel gehalten und ohne Parameter, die irgend etwas steuern. Aber das kann man ja nachträglich einbauen. Wenn man will.

#!/bin/bash                                                                          

intervalo=2
info="/sys/class/net/"
cd $info
while true; do
for interface in eth*
do
  eval rx1$interface=`cat $info$interface/statistics/rx_bytes`
  eval tx1$interface=`cat $info$interface/statistics/tx_bytes`
done
  sleep $intervalo
for interface in eth*
do
  eval rx2$interface=`cat $info$interface/statistics/rx_bytes`
  eval tx2$interface=`cat $info$interface/statistics/tx_bytes`
done
clear
date
for interface in eth*             
do
  echo $interface
  echo ---- 
  rx1=$(eval echo \${rx1$interface})
  rx2=$(eval echo \${rx2$interface})
  tx1=$(eval echo \${tx1$interface})
  tx2=$(eval echo \${tx2$interface})
  echo RX: $((($rx2-$rx1)/($intervalo*1024))) Kbps
  echo RX: $((($rx2-$rx1)/($intervalo*1048576))) Mbps
  echo TX: $((($tx2-$tx1)/($intervalo*1024))) Kbps
  echo TX: $((($tx2-$tx1)/($intervalo*1048576))) Mbps
done
done
Bandbreite anzeigen

Regex

Regex (regular expressions) machen furchtbare Kopfschmerzen. Aber da sie so mächtig sind, braucht man sie immer mal wieder. Und hier ist die Kopfschmerztablette:

http://www.regexr.com/ RegExr is an online tool to learn, build, & test Regular Expressions (RegEx / RegExp).

regexr
So sieht die Seite aus

Auf der Seite kann man per Mouse-over seine RegEx ausprobieren und bekommt jeden einzelnen Teil davon erklärt. Ausserdem gibt es ein „Cheatsheet“ mit gängigen Ausdrücken, Beispiele und vieles mehr. Super!

Regex

MySQL – das letzte

Ich nutze MySQL-Datenbanken um Testergebnisse von automatisierten Testläufen zu speichern. Es kommt dabei oft vor, dass ich von allen Ergebnissen zu einer Testreihe, in der einzelne Tests, die mit einer ID markiert sind und durchaus mehrfach (wiederholt) gemacht werden können, nur das letzte Ergebnis in einer Query haben will. Das geht so:

SELECT * FROM <table> WHERE <my-id-field> IN (SELECT MAX(<id>) FROM <table> GROUP BY <my-id-field>) ORDER BY <my-id-field>;

Wichtig ist, dass man zwei ID-Felder hat. Das erste <id> muss ein auto increment sein, also eine Zahl sein und mit jedem neuen Eintrag in die DB wachsen (das ist sowieso best practice, wenn man eine Tabelle anlegt). Das zweite Feld <my-id-field> ist eine ID einer Reihe von Tests oder Ergebnissen, von denen man nur das letzte Ergebnis haben will. Diese ID muss nicht zwangsläufig eine Zahl sein.

MySQL – das letzte

Filtern in Bash

Manchmal will man aus einer Variable oder einem Text alle Zahlen herausziehen oder verstecken. Das geht natürlich mit sed ganz gut, aber noch einfacher in der Bash selbst.

% VAR=1a2b3c4d
% echo "${VAR//[!0-9]/}"
1234
% echo "${VAR//[0-9]/}"
abcd

Man kann auch nur Buchstaben filtern, damit man Sonderzeichen mit herausfiltert. Oder oder…

% VAR="1a,2b.3c;4d"
% echo "${VAR//[!0-9]/}"
1234
% echo "${VAR//[!a-z]/}"
abcd
% echo "${VAR//[!a-z 0-9]/}"
1a2b3c4d
% echo "${VAR//[a-z 0-9]/}"
,.;
Filtern in Bash