Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

January 22 2012

13:09

MySQL | Table Migration zu InnoDB

Ich durfte letztens einer schönen Schulung zum Thema MySQL lauschen. Dabei kam viel herrum. Ein Teil davon hat sich mit verschiedenen Storage Engines beschäftigt.

Ich habe mich entschieden den Großteil meiner Datenbanken zu InnoDB umzuwandeln. Welche Vor- und Nachteile das hatt sollte sich jeder vorher klarmachen. Stichwort: ACID und Fulltext-Search. Natürlich könnte man einfach mit ALTER arbeiten. Aber ich wollte nicht umbedingt die alten MyISAM Tables noch im FS liegen haben. Also alle Datenbanken droppen und den geänderten Dump wieder einspielen, sodass die Tables neu (mit InnoDB) angelegt werden.

Zuersteinmal eine Liste mit den generieren mit den Datenbanken die man Bearbeiten möchte. Es ist zu beachten, dass man den mysql Table selbst nicht auf InnoDB umstellen möchte.

mysql -u root -p -e "show databases;" -N --batch | grep -v ^information_schema$ | grep -v ^mysql$

Die Liste der Datenbanken wird nachher noch hilfreich sein. Danach will man wahrscheinlich erstmal alle Dienste beenden, die auf dem MySQL zugreifen (Apache, Tomcat, whatever). In der my.cnf habe ich dann folgende Optionen für die InnoDB spezifiziert.

defaulot-storage-engine = InnoDB
innodb_buffer_pool_size = 16M
innodb_additional_mem_pool_size = 2M
innodb_log_file_size = 5M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50

Anschliessend den Dump erstellen und alle ENGINE=MyISAM durch InnoDB ersetzen:

mysqldump -u root -p > all-databases.sql
sed -i -e 's#ENGINE=MyISAM#ENGINE=InnoDB#g' all-databases.sql

Vorsicht. Hier ist mysql als Datenbank mit gedumped! Mir ist dabei keine wirklich einfache Zeile eingefallen die mit Suche/Ersetze Spielchen mysql ausschliesst. Es gibt bei mysqldump die Option “–ignore-table=” aber auch hier hätte ich jeden mysql Table einzeln nennen müssen. Ich hab die Datenbank dann einfach per hand aus dem Dump herausgelöscht.

Außerdem sollte man seinen Datenbank Dump nach FULLTEXT durchsuchen, da dieser von InnoDB nicht unterstützt wird. In meinem Fall hat es nur ein altes Forum das niemand mehr benutzt betroffen, weshalb ich die Zeile einfach löschen konnte.

grep "FULLTEXT" all-databases.sql

Um jetzt alle Datenbanken zu droppen hab ich mir folgende Line gebastelt:

for x in $(mysql -u root -phierstehteinpasswort -e "show databases;" -N --batch | grep -v ^information_schema | grep -v ^mysql$) ; do mysql -u root -phierstehteinpasswort -e "drop database $x ; " --batch ; done

Nach der Bearbeitung kann man den Dump mit der neuen Engine für die Tables wieder einspielen:

mysql -u root -p < all-databases.sql

October 02 2011

21:58

Statistiken | Einfache Graphen mit R und MySQL Anbindung

Immer mal wieder reizt mich die Programmiersprache für Statistiken R. Um diesen Reiz dann auszuleben hab ich vor ein paar Monaten angefangen kleine Graphen für den zufallsbasierten Simulator ZRE zu bauen. Das Spiel “läuft” einfach 24/7 und schreibt für jedes geschehene Event Einträge in die Datenbank. Diese Einträge werte ich dann mit Hilfe von R aus.

Dazu gibt es ein Skript. Nämlich zre.R (Ob das die Konvention bei R-Skriptnamen ist, kann ich nicht sagen ;) )

#!/usr/bin/env Rscript

### General R-Script
# MySQL
library(RMySQL)
con <- dbConnect(MySQL(), user="", password="", host="", client.flag=CLIENT_MULTI_RESULTS)
# Style
zre_colors <- colors()[grep("green",colors())]
zre_mint <- colors()[c(48,86,50)]

Im Klartext wird aus dem CRAN Library Verzeichnis die Library RMySQL includiert und die Verbindung in der Variable con abgelegt. Ähnlich wie bei PHP. Für alle Debian / Ubuntu Benutzer empfiehlt sich aber, die Library einfach über das Paketsystem nachzuinstallieren.

$ aptitude install r-cran-rmysql

Standardmäßig sehen Graphen die mit R erstellt werden ziemlich mau aus. Die weiteren Variablen unter Style habe ich gewählt um mir die Colorierung der Graphen etwas zu erleichtern. Diese werden später einfach als Attribute in den Plots/Barplots gesetzt und ausgewertet. Ich fange einfach mal der Reihe nach an:

Die Abfolge ist immer ziemlich ähnlich. Zu aller Erst wird der Query für die Datenbank an die Variable sql übergeben. Diese Variable wiederrum wird zusammen mit der Connection an die Funktion dbGetQuery übergeben und das Ergebnis dessen schliesslich in zre_wins gespeichert. Anschliessend ein paar kleine Informationen an das Dateiformat übergeben und den Graphen bauen.

Die Funktion par lässt sich erstmal als eine Art Environment Funktion für Graphen verstehen. Hier werden Eigenschaften wie Schriftfarbe, Hintergrund, Axenfarbe, und Liniendicke definiert. Danach kommt (wie ich finde) der schwierigste Teil. Bauen des Graphen. Je nach Art des Graphen (Balken, Linien, Torte u.ä.) werden logischerweise verschiedene Parameter erwartet. Die Daten werden hierbei jetzt als Matrix an ein Balkendiagram übergeben. Weitere Informationen wie die Überschrift (main) und die Beschreibung der Balken (names.arg) werden einfach angefügt.

# Graph: Wins

sql <- paste("SELECT COUNT(id) AS sum, side FROM zombies.zre_wins GROUP BY side;")
zre_wins <- dbGetQuery(con, sql)
png(file="wins.png", width=400, height=400)
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=2)
barplot(as.matrix(zre_wins$sum), main="Game Summary", names.arg=c(zre_wins$side), beside=TRUE, col=zre_mint)

Selbes Spiel wieder, nur mit mehr Balken und anderem Use-Case. Diesmal werden die 25 Konflikte mit den meisten Opfern visualisiert.

# Graph: Highest Kills

sql <- paste("SELECT id, kills FROM zombies.zre_kills ORDER BY kills DESC LIMIT 25;")
zre_matches_highest <- dbGetQuery(con,sql)
png(file="highestkills.png", width = 400, height = 400, bg="transparent")
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=4)
barplot(zre_matches_highest$kills, zre_matches_highest$id, main="25 Highest Kills", beside = TRUE, ylab="Kills", col=zre_colors)

Aber da Balkendiagramme auch irgendwann Langweilig werden geht das natürlich auch anders. Die 25 letzten Konflikte werden im “Opferverlauf” wie folgt dargestellt:

# Graph: Kills

sql <- paste("SELECT kills FROM zombies.zre_kills ORDER BY id DESC limit 25;")
zre_kills <- dbGetQuery(con,sql)
yrange <- range(zre_kills$kills)
xrange <- length(zre_kills$kills)
png(file="kills.png", width=400, height=400, bg="transparent")
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=4)
plot(zre_kills$kills, xlab="Games", type="b", ylab="Kills", main="Kills from last 25 Attacks", col=zre_mint)

Damit es nicht immer nur um Tote geht, auch mal was erfreuliches. Die Geburtenrate in ZRE steigt! :)

# Graph: BirthRate

sql <- paste("SELECT Month(date) AS month, count(id) AS born FROM (SELECT *, Month(date) AS M FROM zombies.zre_born) t Group by M; ")
zre_birthrate <- dbGetQuery(con,sql)
png(file="birthrate.png", width=400, height=400)
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=3)
barplot(zre_birthrate$born, xlab="Month", ylab="Born Humans/Zombies", names.arg=c(zre_birthrate$month),main="BirthRate per Month", col=zre_colors)

Und auch das Wetter soll bei der ganzen Sache nicht zu kurz kommen. Hierbei bitte besonderes Augenmerk auf die Legende rechts oben. Eine direkte Zuordnung der Werte und Farben ist nicht nötig, da die Farben in der selben Reihenfolge von zre_colors befüllt werden wie die Balken. Die erschreckend hohe Zahl an Naturkatastrophen erklärt das aber trotzdem nicht :)

# Graph: Weather
sql <- paste("SELECT COUNT(id) AS count, weather FROM zombies.zre_weather GROUP BY weather ORDER BY count DESC;")
zre_weather <- dbGetQuery(con,sql)
png(file="weather.png", width=400, height=400)
par(col="white", bg="transparent", col.axis="white", col.lab="white", col.main="white", lwd=2)
barplot(zre_weather[,1], main="Weather in ZRE", beside = TRUE, col=zre_colors)
legend( 5, 40000, zre_weather$weather, cex=0.9, fill=zre_colors, col="white")

Das volle zre.R Skript befindet sich wie das meiste auf Github: https://gist.github.com/1031260

August 23 2011

16:39

PostgreSQL | 1000 und 1 Query

Zur Zeit spiele und bastle ich nebenher mit PostgreSQL rum. Überlege ob ich mal eine alternative DB für das Zombie-Revolution-Environment an den Start bringe…

Für meinen Use-Case scheint das allerdings nur begrenzt von Nutzen zu sein. Ich mache vielleicht etwas falsch, aber wenn ich 1000 Queries in MySQL kippe, dauert nur einen Bruchteil so lange wie in postgreSQL. Um das zu veranschaulichen:

$ time for x in $(seq 1 1000) ; do mysql -u root -ppw -e "insert into foobar.foo values ($x, now());" ; done
real 0m7.349s
user 0m0.060s
sys 0m0.380s

$ time for x in $(seq 1 1000) ; do psql --quiet -d foobar -c "insert into foobar values ($x, now());" ; done
real 1m28.363s
user 0m37.450s
sys 0m13.020s

Kann mir jemand sagen woran das liegt? Ich kann mir nur schwer vorstellen das PostgreSQL so hinterher hinkt.

April 29 2011

08:30

Shell-Zauberei | Namensliste in MySQL Datenbank einspeisen

Code
for x in $(mysql --batch -u root --password=passw0rd -e "USE rtdb; SELECT DISTINCT id FROM Users;" | grep -v ^id); do mysql -u root --password=passw0rd -e "USE rtdb; UPDATE Users SET Name=\"$(sed -n $(($RANDOM % $(cat Names | wc -l) +1 ))p Names)\" WHERE id=\"$x\" ;" ; done

Hintergrund
Wie auch schon beim letzten mal dreht es sich wieder um die Anonymisierung der RequestTracker Datenbank für die ich zur Zeit an einem Statistik Tool arbeite. Diesmal will ich aber nicht die EmailAdressen ändern, sondern die Namen der Benutzer. Da ich diese nicht so einfach generieren lassen kann, habe ich mir aus dem Interweb eine Liste mit Namen besorgt und mit diesen Namen die eingetragenen überschrieben. Jetzt kann ich endlich den Post über das Statistik Tool schreiben und mit Beispielen versehen :)

Funktion
Das Ganze läuft wie folgt ab: Für jede ID die ich mittels Datenbank-Verbindung in die For-Schleife einbette, setze ich einen UPDATE Befehl ab, der die Tabelle “Users” und das Feld “Name” aktualisiert. Der Aktualisierungsvorgang passiert aber generisch. Das heisst ich setze den Namen des Users auf einen zufällig ausgewählten neuen Namen aus der Datei “Names”. Das habe ich mit sed -n p FILE gelöst, was sicher auch schöner geht, aber für meine Zwecke hat es ausgereicht.

April 23 2011

16:53

Shell-Zauberei | Emailadressen in MySQL Datenbank anonymisieren

Code
for x in $(mysql -u root --password=passw0rd --batch -e "use rtdb; select id from Users" | grep -v ^id); do mysql -u root --password=passw0rd -e "use rtdb; UPDATE Users SET EmailAddress=\"$x@mail.com\" WHERE id=\"$x\"; "; done
Hintergrund
Ich arbeite seit kurzem an einem kleinen Statistik Tool für den RequestTracker von Bestpractical. Einem Ticket-System. Um Beispiele für dieses Tool generieren zu können, brauchte ich eine manipulierte Datenbank. Datenschutz. EmailAdressen mit anderem Inhalt überschreiben.

Funktion
Im Endeffekt ist es nur eine For-Schleife, die alle User ID’s aus der RequestTracker Datenbank (Table: Users) ausliesst und für jeden gefundenen Eintrag die EmailAdresse auf “ID@mail.com” setzt. So bleiben die Daten auswertbar, sind aber “anonym”.

March 26 2011

12:45

ZRE | SQL Statistik Modul

Ich möchte kurz ein Wort über das SQL Modul verlieren, welches die Statistiken des permanent laufenden Zombie Environments aufzeichnet. Wie mit Sicherheit schon überall auf dem Planeten Erde bekannt ist, passieren in ZRE Events. Diese Hand voll Events lösen (wie der Name vielleicht schon suggeriert) Geschehnisse in innerhalb des Environments aus, welche es gilt statistisch auszuwerten und darzustellen.

Han Solo & Chewbacca

Wie aber erfasse ich solche Informationen am Besten. Ich hatte ehrlich gesagt keine große Lust, in jedes der Events einzeln eine SQL-Verbindung aufzubauen und den gewünschten Query abzusetzen. Ganz zu schweigen von der Problemfallbehandlung (MySQL nicht installiert, Modul in Config nicht aktiviert, MySQL nicht erreichbar usw.) die ich in jedem Event hätte extra behandeln müssen.

events/
├── attack.humans.event
├── attack.zombies.event
├── born.humans.event
├── born.zombies.event
├── building.humans.event
├── collecting.zombies.event
├── die.humans.event
├── die.zombies.event
├── infos.event
├── stats.humans.event
├── stats.zombies.event
├── support.humans.event
├── support.zombies.event
└── weather.event

Stattdessen entschied ich mich ein kleines Modul in Bash zu schreiben, welches eine Hand voll übergebener Daten annimmt und dann in die konfigurierte Datenbank schreibt. Hier am Beispiel des weather.event

case $nature_msg in
1) echo "A volcano explodes." ; zresql weather vulcano ;;
2) echo "An earthquake hits the city." ; zresql weather earthquake ;;
3) echo "A hurricane hits the city." ; zresql weather hurricane ;;
esac

Als erstes übergeben wird immer der gewünschte Modus, in den zresql den Datensatz einordnen soll, danach alle weiteren Informationen die der Struktur nach erforderlich sind.

# Hurricane
$ zresql weather hurricane
# Humans gewinnen einen Kampf und vernichten 643 Zombies
$ zresql kill human 643

Das zresql Modul nimmt die Informationen dann entgegen und leitet es unter den gegebenen Umständen via sqlsend an die Datenbank weiter.

[...]
weather) sqlsend "INSERT INTO zre_weather VALUES (NULL, \"$2\", CURRENT_TIMESTAMP);" ;;
kill) sqlsend "INSERT INTO zre_kills VALUES (NULL , \"$2\", \"$3\", CURRENT_TIMESTAMP);" ;;
[...]

sqlsend ist im Grunde nur eine weitere kleine Funktion die direkt über Kommandozeile den SQL Query abschickt.

sqlsend() {
mysql -e "use $sqldb; $1" --user=$sqluser --password=$sqlpw --host=$sqlhost
}

Mit dieser Lösung bin ich eigentlich relativ zufrieden. Über Verbesserungsvorschläge und Kritik freue ich mich natürlich wie immer. Das ganze Modul ist zusehen auf Github: https://github.com/noqqe/zombie-revolution-environment/blob/master/lib/sqlstats.library.bash

February 24 2011

09:22

Charset | UTF8 für Apache, PHP, MySQL, Debian und WordPress

Nachdem ich die Migration meines Blogs auf meinen neues Stück Blech größtenteils abgeschlossen hatte, wurde ich wieder an den Charset Wirr-Warr von IT-Systemen erinnert. Um meinem Blog seine Umlaute wieder zu beschaffen habe ich folgende Änderungen an verschiedenen Stellen eingespielt. Vorzugsweise immer in den entsprechenden conf.d/ Verzeichnissen, da die Änderungen evtl. beim nächsten Upgrade überschrieben werden könnten.



Apache2 Charset
vim /etc/apache2/conf.d/charset
AddDefaultCharset UTF-8

PHP5 Charset
$ vim /etc/php5/apache2/conf.d/charset.ini
[PHP]
default_charset = "utf-8"
[mbstring]
mbstring.language = utf-8
mbstring.internal_encoding = utf-8
mbstring.http_input = utf-8
mbstring.http_output = utf-8

MySQL Charset
$ vim /etc/mysql/conf.d/character
[client]
default-character-set = utf8
[mysqld]
default-character-set = utf8
character-set-server = utf8
collation-server= utf8_general_ci
init_connect = ‘SET collation_connection = utf8_general_ci’
init_connect = ‘SET NAMES utf8′
[mysqldump]
default-character-set = utf8
[mysqlimport]
default-character-set = utf8
[mysql]
default-character-set = utf8

Debian WordPress Config
$ vim /etc/wordpress/config-blog.url.php
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');
define('WPLANG', 'de_DE.UTF-8');

Debian Locales
$ dpkg-reconfigure locales

Sollte ich es mal wieder brauchen, les ich hier nach.

July 24 2010

14:07

MySQL | Datenbanken einzeln sichern

Bis vor kurzem reichte mir ein volles MySQL-Backup der alle DB’s komplett in ein File gesichert hat. Eine Zeile CronJob.
mysqldump -u root --password=x --all-databases > /pfad/$(date +%Y-%m-%d).sql

Das funktioniert so lange, bis einmal recovered werden muss. Alle DB’s neu einspielen ist dann doch irgendwie kein Spass. Weder von der Dauer noch vom Datenverlust. 25 MB sind jetzt zwar nicht die Welt, aber trotzdem doof wenn etwas verloren geht. Deshalb kombinierte ich mein Voll-Backup mit einem File pro DB. Folgendes Script dient dazu:

#!/bin/bash
pass=
backuppath=/var/cache/mysqlbackups

mysqldump --password=$pass --all-databases > ${backuppath}/$(date +%Y-%m-%d).sql
return1=$?

for x in $(mysql --password=$pass -Bse 'show databases'); do
mysqldump --password=$pass $x > ${backuppath}/$(date +%Y-%m-%d)-${x}.sql
done
return2=$?

if [ $return1 -eq 0 ] && [ $return2 -eq 0 ]; then
logger -p local0.info -t MYSQLBACKUP MySQL Backup successful
else
logger -p local0.err -t MYSQLBACKUP MySQL Backup failed
fi

Ausschlaggebender Teil ist die for-Schleife. Für jede Zeile Output von “show databases” wird ein seperates .sql File erstellt. Versehen mit Datum und DB-Name. Nebenbei wird auch noch via logger in /var/log/syslog geloggt.

March 16 2010

18:19

Event | Chemnitzer Linux-Tage

logo2010

Ein Stück weit, darf hier ruhig auch etwas Privates einziehen. Am Sonntag 14. März war ich zum ersten Mal zu Besuch bei den Chemnitzer Linuxtagen. Die knappen 2 Stunden mit dem Auto habe ich morgens um halb 8 auf mich genommen :) Ich muss sagen ich war relativ begeistert.

IMG_0215

Nach der Ankunft, sah ich mich erst etwas in der Halle um, besuchte Jan am Debian-Stand und liess mich erstmal von durchweg freundlichen Projektvertretern in ihr (mir meistens bereits bekanntes) Projekt einführen.

IMG_0213

Darauf folgte eigentlich ein Marathon aus Vorträgen. Durch einen Umstand konnte ich mich leider nur Sonntags den Vorträgen unterziehen. Aber trotzdem gefielen mir die, die ich sah, sehr gut.

1. Anonymität im Internet (TOR, i2P und grundsätzliches zu Daten)
2. Virtual System Cluster mit KVM und Pacemaker (B1-Systems. Für mich teils interessant für Arbeit. Thema Virtualisierung)
- Mittagspause-
3. Auf dem Weg zum Intrusion Detection System der nächsten Generation (IDS war ein bisschen Unglücklich gewählt. Sehr theoretisch im Bezug auf Social Engineering)#
4. MySQL Backups – Best Practices (Ein Referent mit polnischer Herkunft klärte mich über grösstenteils alle Backuplösungen auf. Hot / Cold / Txt / Binary / Differentiell)
5. Computerviren und Linux (Sehr sehr nice gewesen. Haufen neue Erkenntnisse gehabt)

Im generellen auch netten Kontakt mit den unterschiedlichsten Linux-Anwendern gehabt. Linux@Grundschule Linux@HP und ähnliches.
Werd ich nächstes Jahr gerne wieder besuchen. Vielleicht sogar das ganze WE.

February 24 2010

18:40

FTP | vsftpd mit MySQL-Userauth und fail2ban

Ein Kollege aus dem lokal vertretenen Eishockey-Hobbyverein hatte eine kleine Page mit HTML gebastelt und wollte diese irgendwo hosten.  Hier würde sich von den Mitgliedern um den Informationsfluss gekümmert und da ich selbst öfters an den Spielen teilnehme, half ich natürlich gerne. Ich benutzte bis dato allerdings nie FTP und hatte auch keinen FTP-Server installiert. “Wenn dann schon richtig” war meine Intention. Über ein How-To auf HowtoForge.com richtete ich einen vsftpd mit mysql-userauth ein. Das war innerhalb 15 Minuten geschafft. FTP-Server lief wunderbar und die (noch dürftige) Site ist auch fast online. Mir gefiel die Auth-Möglichkeit über MySQL.

Nichtsahnend durchforstete ich heute Morgen die Logfiles meiner Zwetschge. vsftpd-Logfiles innerhalb 15 Stunden relativ voll. Irgendwas war faul. Nachdem ich die fehlerhafte Konfiguration des logrotated ausschliessen konnte sah ich mir die Logs mal an.

CONNECT: Client "xxx"
[Administrator] FAIL LOGIN: Client "xxx"
[Administrator] FAIL LOGIN: Client "xxx"
[Administrator] FAIL LOGIN: Client "xxx"
CONNECT: Client "xxx"
[Administrator] FAIL LOGIN: Client "xxx"
[Administrator] FAIL LOGIN: Client "xxx"
[Administrator] FAIL LOGIN: Client "xxx"

Ich zählte nicht, wie oft genau. Jedenfalls zu oft um von fehlerfreier Konfiguration meines fail2ban ausgehen zu können. Außerdem ist es beachtlich wie schnell Bots einen existierenden FTP-Server ausmachen können. Was solls. Zur Erinnerung: Fail2ban verbietet (anhand Logfileanalyse) Clients die Verbindung, wenn sie  zu oft abgewiesene Verbindungsversuche gestartet haben. Sprich: Zu viele falsche Passwörter. Stichwort Bruteforce-Attacke

Dies veranstaltet fail2ban mit einem Configfile (/etc/fail2ban/jail.local) und Filtern (/etc/fail2ban/filters.d/*). Ich habe länger überlegt, Config erneuert, fail2ban-server neu gestartet bis mir kam warum die übermäßig vorhandenen failed-logins meines FTP-servers nicht geblockt wurden. Die Ausgabe im Loggingfile hatte sich durch die Umstellung auf MySQL geändert und fail2ban greift nicht mehr:

auth.log(Standard): Jan 23 14:04:14 vsftpd: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=Administrator rhost=xxx
---
auth.log(mysqlauth): Feb 24 12:33:29 zwetschge vsftpd: pam_mysql - SELECT returned no result.

Nach etwas erfolglosen herumgegoogle und anderem, beschloss ich die RegExp für den neuen Filter selbst zu konfigurieren. Der neue Filter basiert nichtmehr auf dem auth.log sondern auf dem vsftpd.log(im jail.local-File vermerken!). fail2ban bietet eine wunderschöne Möglichkeit selbstgecodete Filter auszuprobieren. Via fail2ban-regexp wird ein zu filternder Logeintrag auf ein regexp geprüft.

fail2ban-regexp 'logeintrag' 'regexp zum logeintrag'
http://zwetschge.org/paste/011

In filters.d: die die Regular-Expression des Zugriffs für das StandardLogfile ersetzen:

alt:auth.log(stdregexp): failregex = vsftpd: \(pam_unix\) authentication failure; .* rhost=<HOST>(?:\s+user=\S*)?\s*$
---
neut:vsftpd.log(mysqlregexp): failregex = .* FAIL LOGIN: Client \"<HOST>\"$

Fail2ban neu starten, glücklich sein.
Um zukünftigen Usern diesen Schritt zu erleichtern habe ich natürlich die Änderungen unter das How-To kommentiert. Awating Moderation btw.

January 09 2010

11:16

Mail | Postfix-Aliases mit MySQL-Backend erstellen

Ich registrierte mich vor kurzem wiedermal bei einem etwas zwielichtigem Portal. Keine begründete Behauptung, es schien mir aber trotz allem so vorzukommen. Wie üblich loggte ich mich in meinen PHPMyAdmin ein und erstellte (um SpamEmails vorzubeugen) mithilfe meines MySQL-Backends von Postfix einen Alias. In einer Tabelle gesammelt liegen sämtliche aliase und deren Empfänger-Postfach.

address | goto
ubuntu@zwetschge.org | mail@zwetschge.org
spam2@zwetschge.org | mail@zwetschge.org
spam3@zwetschge.org | mail@zwetschge.org
spam4@zwetschge.org | mail@zwetschge.org

Es mag jetzt mit Sicherheit User geben die MySQL mit Postfix für unnötig halten, da die Steuerung über ConfigFiles ausreicht. Auf kurz oder lang gefällt mir die MySQL einfach besser. Einfach zuhandhaben. Flexibel. Schön. Das ständige eingelogge in HTpasswd, phpmyadmin-login und herumgeklicke war mir grad nur etwas zu blöd. Ich wollte ein kleines Skript basteln das mir das adden von Aliasen per CLI ermöglicht. In etwa so:

aliasadd <alias> <recepient>

Via echo lässt sich mysql (nach Authentifizierung) einen Befehl übergeben:

echo "use maildb; insert into aliases values ('$1', '$2');" | mysql -u <user> --password=<pass>

Damit wäre auch schon das gröbste geschafft. Zumindest das Einfügen. Ein Skript zeichnet allerdings mehr aus als nur die Aufgabe die es erledigen soll. Ein Skript muss zuverlässlich sicherstellen das die Aufgabe ausgeführt wurde und dies dem Benutzer nach Möglichkeit auch noch mitteilen.

echo "use maildb; select * from aliases where address = '$1';" | mysql -u <user> --password=<pass>

Die vorherige Zeile sieht eigentlich nur nach ob der eingegeben Alias wirklich in der Datenbank vorkommt. Freilich(wer findet ‘freilich’ eigentlich noch seltsam in Sätzen?) könnte ich jetzt noch nach Rückgabewerten mit $? Abfragen und ähnliche if-Vorraussetzungen einbauen. Aber für die 4-5 mal im Monat in denen ich es benutze wäre das übertrieben.

Fertig sieht das ganze dann wie folgt aus:

#!/bin/bash
echo "use maildb; insert into aliases values ('$1', '$2');" | mysql -u <user> --password=<pass>
echo "use maildb; select * from aliases where address = '$1';" | mysql -u <user> --password=<pass>

Bildschirmfoto 2010-01-09 um 12.12.35

nochmal als Plaintext:
http://zwetschge.org/paste/6

Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.