PXE Downloader Script für Xbuntu

Script that automatically downloads and prepares ubuntu images (and variants) for pxe boot

#!/bin/bash 
 
 
NFS_HOST="192.168.101.9" 
NFS_BASE_PATH="/netboot/tftp" 
FLAVOUR_MIRROR="http://www.mirrorservice.org/sites/cdimage.ubuntu.com/cdimage"  #original ubuntu does not exist on that mirror for amd64 arch 
UBUNTU_MIRROR="http://releases.ubuntu.com" 
ARCH="amd64" 
AVAILABLE_FLAVOURS=['ubuntu','kubuntu','xubuntu','lubuntu','ubuntustudio','edubuntu'] 
 
 
set -e  # exit on error 
 
 
if [ "$1" == "" ] || [ "$2" == "" ] || [ "$3" == "" ] || ! echo ${AVAILABLE_FLAVOURS[@]} | grep -q -w "$1"; 
then 
        echo "Arguments: FLAVOUR CODENAME VERSIONNUMBER" 
        echo "e.g.: xubuntu xenial 16.04.2" 
        exit 1 
fi 
 
flavour=$1 
codename=$2 
version=$3 
variant="desktop" 
 
if [ -e "${flavour}_live/${codename}-${variant}-${version}/" ]; 
then 
        echo "Already exists" 
        exit 1 
fi 
 
 
if [ "$1" == "ubuntu" ]; 
then 
        IMAGE_MIRROR=$UBUNTU_MIRROR/${codename} 
else 
        IMAGE_MIRROR=$FLAVOUR_MIRROR/${flavour}/releases/${codename}/release 
fi 
 
 
wget -O /tmp/image.iso ${IMAGE_MIRROR}/${flavour}-${version}-${variant}-${ARCH}.iso 
mkdir -p ${flavour}_live/${codename}-${variant}-${version}/ 
7z x -o${flavour}_live/${codename}-${variant}-${version}/ /tmp/image.iso 
chmod -R +rx ${flavour}_live/${codename}-${variant}-${version}/ 
rm /tmp/image.iso
 echo "${NFS_BASE_PATH}/${flavour}_live/${codename}-${variant}-${version}       192.168.0.0/255.255.0.0(ro,async,subtree_check,no_root_squash)" >> /etc/exports 
/etc/init.d/nfs-kernel-server restart 
 
 
 
if ! [ -e "pxelinux.cfg/${flavour}_live" ]; 
then 
 
 
echo " 
LABEL      ${flavour} 
MENU LABEL ${flavour} ^Live 
KERNEL     vesamenu.c32 
APPEND     pxelinux.cfg/${flavour}_live 
" >> pxelinux.cfg/default 
 
echo " 
DEFAULT vesamenu.c32 
ALLOWOPTIONS 0 
PROMPT 0 
TIMEOUT 0 
 
MENU TITLE PXE Boot Menu - ${flavour} 
 
LABEL      back 
MENU LABEL <- 
KERNEL     vesamenu.c32 
APPEND     pxelinux.cfg/default 
" >> pxelinux.cfg/${flavour}_live 
 
fi 
 
 
echo "" >> pxelinux.cfg/${flavour}_live 
echo "LABEL ub${codename} ${version}" >> pxelinux.cfg/${flavour}_live 
echo "MENU LABEL ${flavour} ${codename} ${version} (${variant})" >> pxelinux.cfg/${flavour}_live 
echo "KERNEL ${flavour}_live/${codename}-${variant}-${version}/casper/vmlinuz.efi" >> pxelinux.cfg/${flavour}_live 
echo "APPEND root=/dev/nfs boot=casper netboot=nfs nfsroot=${NFS_HOST}:${NFS_BASE_PATH}/${flavour}_live/${codename}-${variant}-${version} initrd=${flavour}_live/${codename}-${variant}-${version}/casper/initrd.lz nomodeset -- locale=de_DE console-setup/layoutcode=de" >> pxelinux.cfg/${flavour}_live

 

Projekt: 2m x 2,20m Bett im Blockhausstil

Vor drei Jahren standen meine Frau und ich vor der Aufgabe, ein ausreichend großes Bett zu finden, mit angenehmer Einstiegshöhe, in stabil und nicht zu teuer. Nach einiger Zeit wurde klar, dass das nicht so einfach vereinbar ist und sind schließlich zu dem Punkt gekommen, das Ganze selbst in die Hand zu nehmen.

Da wir nun in der Situation sind, dass wir ein weiteres Bett für unser Gästezimmer bei den lieben Schwiegereltern brauchen, haben wir die alten Pläne wieder rausgeholt. Dieses mal möchten wir das Ganze ein bisschen dokumentieren, damit vielleicht auch andere etwas davon haben.

Zuallererst habe ich mal in Sketchup ein 3D-Modell gebaut, damit man genau sieht, wie es später aussehen soll.

 

Materialliste:

  • Konstruktionsvollholz (100x100mm; je etwas länger kaufen als angegeben, um nachher sauber kürzen zu können):
  • Holzlatten (35x50mm)
    • 2 Stück in Länge 1,70m
    • 4 Stück in Länge 0,80m
    • 4 Stück in Länge 2,20m
  • Holzlatten (25x50mm)
    • 35 Stück in Länge 2,00m
  • Gewindestangen (M10)
    • 4 Stück in Länge ca. 32-33cm, ggf. länger kaufen und selbst später zuschneiden
  • Hutmuttern (M10)
    • 4 Stück M
  • Kopfstücke mit M10 Gewinde (alternativ 4 weitere Hutmuttern)
  • 4 bzw. 8 Unterlegscheiben für M10 Gewinde
  • Holz-Senkkopfschrauben (wegen der Längen vorzugsweise TORX)
    • ca. 60 in 6x160mm (Gewinde ca. 70mm)
    • ca. 20 in 5x70mm (Gewinde ca. 40mm)
    • ca. 32 in 5x60mm (Vollgewinde)
    • ca. 140 in 5x40mm (Gewinde 25mm)
  • 4 Winkelverbinder
  • Lein-Öl oder Holzlack zur Beschichtung, je nach Präferenz

Das Konstruktionsvollholz bekommt man im Holzhandel oft in 6 Meter Stücken. Meistens kann es aber zum Transport wenigstens grob in kleinere Stücke gesägt werden. Das die Stücke dabei erst etwas länger bleiben ist nicht weiter tragisch, da die ohnehin nochmal sauber durchgesägt werden sollten. Es macht aber auf jeden Fall Sinn, sich vorher schon einmal zu überlegen, wie man die Stücke kombiniert, um möglichst wenig 6m Stücke kaufen zu müssen.

Werkzeug:

  • Akkuschrauber und/oder Bohrmaschine
  • Exzenterschleifer
  • Langer Holzbohrer (>30cm)
  • ggf. Oberfräse um die Kanten schön abzurunden
  • Säge (mit Schnitttiefe >10cm)
  • Auflegeböcke
  • Lappen oder Pinsel (je nachdem, ob das Holz mit dem Öl oder dem Lack beschichtet wird)

Arbeitsschritte:

to be continued…

Emails für bestimmte Empfängerdomains über Smarthost senden

Ich hatte kürzlich einen Fall, bei dem die Emaildienste eines großen Betriebssystemherstellers alle Mails von einer Seite abgelehnt haben, die einige Zeit vorher von einem auf einen anderen Server umgezogen ist.

Da „nur“ die IP des neuen Servers in der Blockierliste eingetragen war, war es weiterhin möglich, Mails vom alten Server zu senden. Da es nun etwas dringend war, dass die Emails wieder an die Kunden des Mailproviders gehen und eine Löschung von der Blockierliste zu lange dauert, hab ich mich dazu entschieden, die Mails erst einmal über den alten Server zu senden. Dieser agiert somit als sog. Smarthost.

Damit aber die IP-Reputation für andere Mailprovider nicht sinkt, sollten nur die Mails über den Smarthost gesendet werden, die tatsächlich an die betroffenen Domains gehen.

Um exim entsprechend zu konfigurieren, habe ich folgende Konfigurationsdatei angelegt (Wichtig: Split-Files-Mode aktivieren)

/etc/exim4/conf.d/router/049_exim4_config_specific_mail_via_smarthost

mit diesem Inhalt:

static_route:
    driver = manualroute
    transport = remote_smtp
    route_data = ${lookup{$domain}partial-lsearch{/etc/exim4/specific_relays}}

Dazu dann eine Datei, in der den Domains ein Smarthost zugewiesen wird:

/etc/exim4/specific_relays

Inhalt:

xyz.com: smarthost.example.com
xyz.de: smarthost.example.com

Zu guter Letzt noch auf dem Smarthost die Annahme vom Absendeserver erlauben. Das lässt sich bei Debian-basierten Distributionen einfach über einen der Dialoge der Konfiguration erledigen (Dialog Relay-Host):

dpkg-reconfigure exim4-config

Smarthost-Konfiguration
Smarthost-Konfiguration

Dann auf beiden Systemen den Exim-Dienst neu laden:

service exim4 reload

Idee:

https://forums.cpanel.net/threads/forward-certain-domain-emails-to-smart-host.136325/#post-899191

Clusterize.js

Sehr lange Listen in HTML-Dokumenten sind nicht unbedingt eine gute Idee. Vor allem auf Mobilgeräten wird die ganze Seite ab wenigen hundert Einträgen sehr träge oder der Browser stürzt gleich ganz ab, wenn das Gerät zu wenig Arbeitsspeicher hat. Zumindest habe ich das auf alten iOS Geräten schon erlebt.

Eine sehr elegante Möglichkeit das zu umgehen ist Clusterize.js. Hier werden nur die Teile der Liste tatsächlich als Element dargestellt, die auch sichtbar sind. Der Rest wird aus dem DOM entfernt. Um aber trotzdem ein korrektes Scrollen zu ermöglichen, werden die nicht sichtbaren Teile der Liste mit Platzhaltern ausgefüllt, die dann so hoch wie die versteckten Elemente sind.

Clusterize.js Beispiel
Clusterize.js Beispiel

Trashmail-Anbieter ausschließen

Zugegeben, wenn man mal kurz eine Mailadresse braucht und nicht seine eigene hergeben möchte sind temporäre Emailadressen höchst praktisch. Zum Problem werden sie aber wenn man selbst einen seriösen Dienst betreibt und bestimmte Personen diese Adressen immer wieder verwenden um ihr Unwesen zu treiben. Hier ist es meist hilfreich die entsprechenden User auszuschließen oder besser, unter besondere Beobachtung zu stellen.

Ich habe zu diesem Zweck eine ganze Reihe von Anbietern zusammengesucht und auch direkt ein passendes PHP-Script gestrickt. Vielleicht kann es ja mal wer brauchen:

function in_array_endswith($haystack, $needle){
return array_reduce($haystack, function($carry, $item) use ($needle){
      if($carry == null){
      $carry = false;
      }
      return $carry || ($item === "" || (($temp = strlen($needle) - strlen($item)) >= 0 && strpos($needle, $item, $temp) !== FALSE) );
   });
}

function is_trashmail($mail){
   $tms = file("trashmails.txt", FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);
   return in_array_endswith($tms, strtolower($mail));
}

trashmails.txt:

@0815.ru
@10minutemail.com
@12minutemail.com
@1pad.de
@3d-painting.com
@anonmails.de
@anonymbox.com
@antichef.net
@BeefMilk.com
@bio-muesli.info
@bio-muesli.net
@byom.de
@cust.in
@deadaddress.com
@despammed.com
@DingBone.com
@discardmail.com
@discardmail.de
@dispostable.com
@dontsendmespam.de
@edv.to
@emailgo.de
@emailias.com
@emailtemporanea.net
@ero-tube.org
@film-blog.biz
@filzmail.com
@FudgeRub.com
@geschent.biz
@getmails.eu
@great-host.in
@guerillamail.org
@guerrillamail.biz
@guerrillamailblock.com
@guerrillamail.com
@guerrillamail.de
@guerrillamail.net
@imails.info
@jetable.com
@jetable.org
@junk.to
@kulturbetrieb.info
@kurzepost.de
@LookUgly.com
@mail4trash.com
@mailexpire.com
@mailinator.com
@mailnull.com
@mailtome.de
@mintemail.com
@mytrashmail.com
@nervmich.net
@nervtmich.net
@nomail2me.com
@no-spam.ws
@nowmymail.com
@nurfuerspam.de
@objectmail.com
@owlpic.com
@proxymail.eu
@rcpt.at
@recode.me
@s0ny.net
@safetypost.de
@sandelf.de
@schafmail.de
@secretemail.de
@sharklasers.com
@sinnlos-mail.de
@SmellFear.com
@sneakemail.com
@snkmail.com
@sofort-mail.de
@spam4.me
@spamavert.com
@spambog.com
@spambog.de
@spambog.ru
@spambox.us
@spamex.com
@spamfree24.org
@spamgourmet.com
@spam.la
@spaml.de
@spammedic.com
@spammotel.com
@spamtrail.com
@spoofmail.de
@squizzy.de
@super-auswahl.de
@teewars.org
@tempemail.net
@tempinbox.com
@temporarily.de
@trash2009.com
@trash4.me
@trashemail.de
@trashmail.at
@trash-mail.at
@trash-mail.com
@trashmail.de
@trashmail.me
@trashmail.net
@trashmail.ws
@wasteland.rfc822.org
@watchfull.net
@watch-harry-potter.com
@wegwerfadresse.de
@wegwerfemail.de
@wegwerf-email.net
@wegwerf-emails.de
@wegwerfmail.de
@wegwerfmail.net
@wegwerfmail.org
@wh4f.org
@willhackforfood.biz
@x.ip6.li
@yopmail.com
@zehnminutenmail.de

IPv6 – Der aktuelle Stand

Da ich von Berufs wegen viel mit Netzwerken zu tun habe, verfolge schon seit einiger Zeit den aktuellen Stand bezüglich des neuen IP Standards IPv6. Ich hatte einige meiner Webseiten bereits darauf umgestellt, sodass diese das Protokoll neben IPv4 unterstützen. Der Haken an der Sache war bislang, dass ich das Ganze immer nur in beschränktem Maße testen konnte, da ich ausschließlich eine IPv4 Adresse von meinem Provider zugeteilt bekomme. So kam es dann dazu, dass ich meinen Router endlich auf den aktuellen Stand brachte und meinen SixXS-Tunnel konnektierte. Da das Ganze funktioniert wunderbar.

Nun wollte ich es aber wissen: Welche Internetseiten sind denn eigentlich bereits über IPv6 erreichbar? Wieviel Prozent der Internetdiensteanbieter sind IPv6 fähig?

Ich erinnerte mich daran, dass ich vor einiger Zeit schon einmal einen Webcrawler mit crawler4j programmiert habe. So war dieses Framework auch diesmal meine erste Wahl um „mal eben schnell“ einen IPv6-Tauglichkeits-Scanner zu bauen.

Ich habe mich dazu entschieden, dass der Crawler so vorgehen soll, dass er für jede Domain, die er besucht, maximal 15 Unterseiten abruft. So werden die Server nicht unnötig belastet – der Inhalt der Unterseiten interessiert mich ja eh nicht. Die auf den Unterseiten enthaltenen Links werden jeweils benutzt, um weitere Seiten zu finden. Für jede Domain wird dann schließlich noch ermittelt und protokolliert, ob ein AAAA-Eintrag im DNS vorliegt oder nicht.

Ich habe das Ganze dann mal für einige Zeit laufen gelassen und hier sind meine Ergebnisse (Stand 23. Januar 2015):

 

Untersuchte Domains Erreichbar per IPv6 Nicht Erreichbar per IPv6 Besuchte Unterseiten
49300 2219 47081 203734

Das ergibt einen Anteil von 4,50%.

Ziemlich wenig wie ich finde. Das Ganze ist natürlich kein Beinbruch, da auch alle IPv6 Anschlüsse mindestens über ein IPv4 Carrier-Grade-NAT angebunden sind. Ich hätte aber bei meinem Test deutlich mehr erwartet. Überrascht hat mich auch, das einige sehr große IT-Firmen und Institutionen (Apple, Adobe, Amazon, w3.org) noch kein IPv6 unterstüzen.

Thumbnails mit mogrify erstellen ohne die Köpfe abzuschneiden

Ich hatte kürzlich wieder das Problem, dass ich Thumbnails für eine Bildergalerie erzeugen wollte. Ich finde dabei quadratische Thumbnails am besten, da dann die Übersicht über das Album am gleichmäßigsten aussieht. Blöd ist dabei nur, dass man entweder einen Rahmen um die Bilder hat oder die Bilder beschnitten werden. Ich ziehe hier aber letztere Variante vor, da die Details dann besser zu sehen sind. Ich setzte dann meist ein Lightbox-Plugin ein, dann sieht man die ausgeblendeten Teile ja im Vollbild wenn man drauf klickt.

Um die Thumbnails zu generieren hat sich für mich folgende Methode als sinnvoll erwiesen:

Bei Landscape-Fotos wird einfach ein Quadrat mit der Seitenlänge gleich der Höhe des Fotos verwendet. Rechts und Links wird zu gleichen Teilen abgeschnitten.

Im Landscape-Format klappt das Ganze wunderbar
Im Landscape-Format klappt das Ganze wunderbar

So weit so gut. Wendet man nun das selbe Verfahren bei Portraitfotos an und schneidet oben und unten zu gleichen Teilen ab, hat man oft das Problem, dass die Köpfe oben abgeschnitten werden.

Während das gleiche Vorgehen im Portrait-Format bei Arny wunderbar funktioniert, stößt das spätestens bei mir an seine Grenzen
Während das gleiche Vorgehen im Portrait-Format bei Arny wunderbar funktioniert, stößt das spätestens bei mir an seine Grenzen

Deshalb verwende ich normalerweise immer den oberen Teil des Bildes. Dies hat zwar den Nachteil, dass Bilder, bei denen die Gesichter tatsächlich im unteren Bereich sind, gar nicht mehr zu sehen sind, zumindest bei meinen Fotos war dies aber nur bei einem verschwindend geringen Teil der Bilder der Fall. Sehr viel öfter hatte ich oben angeschnittene Köpfe.

Wenn immer nur der obere Teil benutzt wird, klappts besser.
Wenn immer nur der obere Teil benutzt wird, klappts besser.

Um dieses Verfahren nun schnell auf eine große Menge von Bildern anzuwenden, verwende mogrify mit folgendem Aufruf:

mogrify -auto-orient -thumbnail 145x145^ -gravity North -extent 145x145 *.jpg

Achtung: mogrify überschreibt die Originaldateien! Deshalb am besten vorher in ein separates Thumbnail-Verzeichnis kopieren. Alternativ kann man die gleichen Parameter auch mit convert verwenden, dann muss man aber sowohl Ein- als auch Ausgabedatei angeben.

Da ich das Ganze auch öfter mal in PHP-Code verbaue, habe ich mir eine kleine Klassenbibliothek geschrieben, die neben normalen Vergrößerungs-Operationen auch das Cropping mit Fokus auf den oberen Teil unterstützt:

PHP Resize Lib

Weiter verbessern ließe sich das Ganze höchstens noch, wenn man eine Gesichtserkennung nutzt. Dann kann man gezielt den Bildausschnitt verwenden, auf denen die (meisten) Köpfe zu sehen sind.