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

copy-paste mit base64

Ich arbeite oft auf Systemen, die ich nur über einen virtuellen Screen erreiche (Remote Desktop etwa) und zu dem ich zwar eine gemeinsame Zwischenablage habe (copy-paste), aber keine einfache Möglichkeit, Dateien zu kopieren.

Wenn ich etwa eine Logdatei kopieren will, die in den Scrollback-Buffer des Terminalfensters auf der remote Maschine nicht komplett reinpasst, dann muss ich stückeln und bereichsweise kopieren. Das nervt tierisch.

Oder ich nutze gzip und base64:

% cp grosselogdatei.log /tmp
% cd /tmp
% gzip grosselogdatei.log
% base64 grosselogdatei.log.gz
H4sICLiyGlkAA29wZW5maWxlcy5jc3YAbZ3dlsSoCkbvz7PUmVWg+DPv/2BTnZgIuG/3oo35AoiS
VMv3n6/9o1/p/5f+77d+mv5PApPvp1li+v30llj52fXE6o99E7Mfk8DGv98fG4md1x1/1z3+toDd
33VLYn/XjXOef9eVKgkKGO [...]
B5SBkg6GOjwNjG+maEv+4PabgVJ+aBgX7iekIn32poGSDg3zQ8O4aKhDR39wL8wFSutmRx06+oP7
CalAKT/0/YJUoKRDx7jo+8XBSEGzgevFQH8YmCfH/mnWQMkfBsbFQH8YGBf3frOle7v3m9drf4FS
XAz0h4k6TMwPE/3BNTACVbg39xNSgb7nUZGiLfnDxLi495tZHbff3FS+tF7I/sni/wA6SY/SD4IA
AA==

Diesen ASCII Output kann ich locker per copy-paste in einem Rutsch kopieren und in eine Datei lokal kopieren, etwa grosselogdatei.log.gz.b64, und wieder auspacken:

% base64 -d grosselogdatei.log.gz.b64 > grosselogdatei.log.gz
% gunzip grosselogdatei.log.gz
copy-paste mit base64

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

Mehrere Variablen in bash gleichzeitig setzen

Wenn ich mit den Output von einem Befehl mehrere Variablen setzen will, kann ich dafür read und die <<< Dreieckklammern nutzen. So gehts:

% EINS=2
% ZWEI=1
% read EINS ZWEI <<< $({ echo 1; echo 2 ; })
% echo $EINS $ZWEI
1 2

Wenn man auf Google oder Bing nach <<< sucht, findet man nichts. Also, entweder bin ich der erste (!!!11!1!!elf!!11), der darüber schreibt, oder wahrscheinlicher, nach diesem String darf man aus technischen Gründen einfach nicht suchen.

Mehrere Variablen in bash gleichzeitig setzen

HTML emails mit mail.mailutils

Das Programm mail.mailutils (meist einfach mail) ist auf vielen Linux-Distributionen installiert. Man kann damit über die Shell Emails verschicken, was sehr praktisch ist für scripte und cron-jobs, die den Admin per Mail informieren sollen.

Manchmal will man auch mal ein wenig mit HTML spielen und sei es auch nur, um um den Text ein <pre> zu setzen, damit er mit einer Monospace-Schrift angezeigt wird und ASCII-Art und Tabellen ordentlich dargestellt werden.

So schickt man HTML:

# generiere random boundary
BOUNDARY=$(date | md5sum | head -c8)
echo "
--_$BOUNDARY_
Content-Type: text/html; charset=\"us-ascii\"
Content-Transfer-Encoding: quoted-printable

<html><pre>
Meine Tabelle

+-------+----------+
| id    | analysis |
+-------+----------+
| 36190 |      219 |
| 36192 |      219 |
| 36273 |      219 |
| 36275 |       -1 |
| 36276 |       -1 |
| 36289 |      219 |
| 36293 |      122 |
| 36371 |      219 |
| 36388 |      219 |
| 36393 |      219 |
| 36394 |       -1 |
| 36395 |       -1 |
| 36708 |      122 |
+-------+----------+
</pre></html>
--_$BOUNDARY_--

" | mail.mailutils -s "Mein Subject" \
-a Content-Type:"multipart/alternative; boundary="\"_$BOUNDARY_\"" \
-a From:mein@absender.tld mein@empfaenger.tld

Diese Tabelle sieht jetzt sauber aus, wenn sie den Empfänger erreicht. Die Leerzeilen vor und nach dem Boundary und/oder Headern sind wichtig!

Wenn ich ein Bild in das HTML einbetten will, wird es komplizierter. Das mail-Tool kann zwar mit -A Anhänge verschicken, aber die kann ich dann nicht im HTML nutzen, da ich die dazugehörige ID nicht kenne.
Also muss ich das händisch machen, damit ich alle Parameter kontrollieren kann. Da Email ein 7-Bit Medium ist, muss ich aus dem Binär-Bild ASCII machen und dann noch dem Mailprogramm erklären, wie es das ASCII wieder in eine Binär-Bilddatei zurückverwandelt. Ich benutze hier base64 dafür, da das standardmässig installiert ist und so ziemlich jedes Mailprogramm das versteht. Ausserdem muss ich dem Bild einen Namen geben, denn der Dateiname geht verloren beim encoden in base64, und dazu eine ID, mit der ich darauf verweisen kann im HTML-Code der Mail. So gehts:

# generiere random boundary und Image ID
BOUNDARY=$(date | md5sum | head -c8)
IMAGEID=$(date | md5sum | head -c10 | rev)
# meine Bilddatei
IMAGEFILE=graph.png
( echo "
--_$BOUNDARY_
Content-Type: text/html; charset=\"us-ascii\"
Content-Transfer-Encoding: quoted-printable

<html>
Mein Graph als Bild:<br>
<img contenttype=3D\"image/png\" src=3D\"cid:$IMAGEID\"><br>
Sieht gut aus!

</pre></html>

--_$BOUNDARY_
Content-Type: image/png;name=\"$IMAGEFILE\"
Content-Disposition: attachment;filename=\"$IMAGEFILE\"
Content-ID: <$IMAGEID>
Content-Transfer-Encoding: base64 
"
base64 $IMAGEFILE 
echo "
--_$BOUNDARY_--" ) |  mail.mailutils -s "Mein Subject" \
-a Content-Type:"multipart/related; boundary="\"_$BOUNDARY_\""; type="\"multipart/alternative\""" \
-a MIME-Version:"1.0" \
-a From:mein@absender.tld mein@empfaenger.tld

Es gibt ausser mail.mailutils noch viele andere Commandline-Mailer wie etwa mutt oder mailx. Mit Hilfe der Beispiele oben kann man auch diese Mailer dazu bringen, HTML zu verschicken. Einfach mal gucken, welche Tools auf dem System installiert sind. Auch OS X kann das.

HTML emails mit mail.mailutils

DNS und TTL

Ich kann ja verstehen, dass Google und auch OpenDNS mit ihren öffentlich zugänglichen Resolvern sich nicht so ganz an die Regeln halten (siehe unten). Sie behaupten zwar das Gegenteil:

Does Google Public DNS comply with the DNS standards set forth by the IETF?
Yes.

Aber so ganz stimmen tut das meines Erachtens nicht. Ich musste einen Dienst von einem Server auf einen anderen umziehen. So bin ich vorgegangen:

  1. Am Tag vorher TTL auf 300 Sekunden (5 Minuten) für den A record heruntersetzen und Seriennummer aktualisieren
  2. Am Tag der Umschaltung auf den Webservern (um die geht es hier) eine Baustellenseite einrichten
  3. Den DNS record umstellen, Zone neu laden und auch auf dem secondary einen Zonenrefresh anstossen
  4. Prüfen, dass die beiden autoritativen DNS Server richtig reagieren
  5. warten, dass 8.8.8.8 endlich auch die neuen Daten liefert

Dummerweise hatte ich vergessen, noch einen Hostnamen für den alten Server einzurichten, also alt.meine-domain.tld, damit ich dort noch Zugriff auf die Seite habe. Also:

  1. DNS Eintrag für A record alt eintragen

Mein SOA sieht so aus:

;; ANSWER SECTION:

meine-domain.tld. 86400 IN SOA adns1.eu-rack.com. ns.eu-rack.co.il. 2016081801 28800 7200 604800 86400

Der A record für www so:

;; ANSWER SECTION:

www.meine-domain.tld. 300 IN A 11.12.13.14

Passt also. Aber: 8.8.8.8 macht aus den 300 Sekunden eine Zufallszahl kleiner 300. Und sowohl der neue A record Eintrag für alt. und der veränderte A record für www. wurden erst nach über vier Stunden aktiv! Dabei habe ich auf der von Google bereitgestellten URL den Cache „geflushed“, wie sie es nennen: https://developers.google.com/speed/public-dns/cache

Vier Stunden passen mit keinem der Zeiten in meinem SOA zusammen. Dort gibt es 24h, 2h und noch andere, aber keine 4h. Alles ziemlich doof. Der Grund ist wohl, dass sie damit effektiv DNS tunneling und DNS DDoS Angriffe vereiteln. Aber dass es mir so das Leben zur Hölle macht, ist doch auch nicht wirklich cool.

iptables auf dem alten Server hat mir dann den Arsch gerettet. Alle Anfragen auf die IP werden weiter geleitet. Das ging aber nur, weil ich eine eigene IP für diese Webseite hatte und keine anderen Vhost darüber liefen:

echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -d [OLD_IP] -p tcp --dport 80 -j DNAT --to-destination [NEW_IP]:80
iptables -t nat -A PREROUTING -d [OLD_IP] -p tcp --dport 443 -j DNAT --to-destination [NEW_IP]:443
iptables -t nat -A POSTROUTING -j MASQUERADE

Als Google dann sich endlich erbarmt hat, habe ich sie wieder gelöscht mit

iptables -t nat --flush

Den Eintrag für alt. konnte ich natürlich in der Zeit vergessen.

Gibt es eine Möglichkeit, dafür zu sorgen, dass das beim nächsten Umzug nicht wieder passiert? Wie bekomme ich Google und OpenDNS dazu, sich so zu verhalten, wie es sich gehört?

DNS und TTL