Linux^2

Linux^2

What you may find here

In this blog you'll mainly find all things Linux - problems, solutions, reports, rants, tips & tricks etc. with the occasional off-topic entry thrown in. You never would have guessed looking at the URL, huh?
In diesem Blog findet ihr hauptsächlich Themen rund um Linux - Probleme, Lösungen, Berichte, Meinungen, Tips & Tricks und dazwischen ein paar überhaupt nicht dazu passende Einträge. Wärt ihr bei der URL nie drauf gekommen, ne?

Mailt mal! Email me!

Proxies mit Perl, LWP und SSL nutzen

LinuxPosted by Jochen Wed, September 07, 2011 17:05:25
Das Problem:
Für ein kleines Projekt habe ich kürzlich eine Website abrufen und analysieren wollen. In Perl wahrlich kein Problem, die LWP-Module nehmen einem fast alle Arbeit ab. Allerdings hatte die einfache Aufgabe zwei kleine Haken, die sich in Summe zu einem Nachmittag "Recherchieren & Ausprobieren" ergänzten. Welche?

  • Die Kommunikation muss durch einen Proxy gehen
  • Die Website ist zwar per http zu erreichen, leitet aber direkt per Refresh auf die https-Version der Site weiter.

Grundsätzlich muss LWP erstmal mit SSL (dem "s" von "https") umgehen können. Dazu muss das Modul Crypt::SSLeay installiert sein. Liest man nun die Dokumentation zu LWP, sollte die folgende Vorgehensweise funktioneren:

Entweder die Umgebungsvariablen

http_proxy
ftp_proxy
https_proxy


(kleingeschrieben!) setzen und (wenn $ua unser LWP-Useragent ist)

$ua->env_proxy;

aufrufen. Oder direkt innerhalb von Perl

$ua->proxy( [ 'http', 'ftp', 'https' ], 'http://mein.proxy.de/3128');

aufrufen. Danach sollte jeder Request durch den Proxy geleitet werden. Das funktioniert sogar - aber leider nur mit Proxies, die wie mod_proxy des Apache Webservers funktionieren.

Andere Proxies wie der weit verbreitete Squid oder auch der MS-ISA verstehen die Methode von LWP aber nicht. Dummerweise gibt es keine Fehlermeldung, sondern ein "200 OK" für die Verbindung, aber mit leerem Body. Gemeint ist damit das Ergebnis für's GET zum Proxy, welches aber im Falle einer HTTPS-Verbindung ein CONNECT sein müsste...

Die Lösung:
Damit LWP::UserAgent für HTTPS-Verbindungen nicht seine fehlerhafte bzw. unpassende Art des Verbindungsaufbaus verwendet, darf für LWP kein Proxy für https gesetzt werden. Für http/ftp-Verbindungen jedoch muss der Proxy wie gewohnt gesetzt sein! Das Proxying für die HTTPS-Verbindungen übernimmt statt dessen Crypt::SSLeay, was für LWP::UserAgent vollkommen transparent ist.

Wie stellt man nun das Proxying für Crypt::SSLeay ein? Hier hilft die Dokumentation zum Modul weiter. Crypt::SSLeay beachtet einige Umgebungsvariablen, wobei hier HTTPS_PROXY (*Großschreibung beachten*) zum Zuge kommt. Auch hier eine kleine Falle, die es zu umgehen gilt: Die Schreibweise

HTTPS_PROXY=http://mein.proxy.de:3128/

funktioniert nicht, da Crypt::SSLeay vom abschließenden "/" irritiert wird. Die korrekte Schreibweise lautet also

HTTPS_PROXY=http://mein.proxy.de:3128

In der Praxis würde man entweder komplett auf Umgebungsvariablen zurückgreifen oder direkt im Perlskript alle notwendigen Werte setzen. Daher skizziere ich hier mal beide Herangehensweisen.

Proxying per Umgebungsvariablen:
In der Shell

PROXY=http://mein.proxy.de:3128 # Kein / am Ende!
http_proxy=$PROXY # Fuer LWP, kleingeschrieben
ftp_proxy=$PROXY # Fuer LWP, kleingeschrieben
HTTPS_PROXY=$PROXY # Fuer Crypt:SSLeay, großgeschrieben
export http_proxy ftp_proxy HTTPS_PROXY


und dann im Skript

use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
$ua->env_proxy;


Proxying komplett im Skript:

use LWP::UserAgent;
my $ua = LWP::UserAgent->new();
my $proxy = 'http://mein.proxy.de:3128'; # Kein / am Ende!
$ua->proxy( [ 'http', 'ftp' ], $proxy); # Fuer LWP
$ENV{'HTTPS_PROXY'} = $proxy; # Fuer Crypt::SSLeay


In einigen Forumthreads im Web fand ich Diskussionen über den Zeitpunkt, an dem die Umgebungsvariable HTTPS_PROXY im Perlskript zu setzen sei. Die oben aufgeführte Variante funktioniert hier bei mir unter Perl 5.10.1 (Kubuntu 11.04), andere hatten scheinbar mehr Erfolg, wenn HTTPS_PROXY vor dem Laden der Module gesetzt wurde:

BEGIN { $ENV{'HTTPS_PROXY'} = $proxy; }
use LWP::UserAgent;


Damit sollte das Problem endgültig erschlagen sein. Die gleiche Vorgehensweise ist übrigens auch bei allen anderen Modulen nötig, die auf LWP zum Herunterladen von Daten per HTTP/HTTPS zurückgreifen, wie zum Beispiel WWW::Mechanize oder WWW::Mechanize::Shell.

Ich hoffe, der Tipp spart irgendjemand da draußen ein paar Stunden Herumbasteln...

bash: read unterstützt Zeilen mit NULL-Ende

LinuxPosted by Jochen Mon, June 27, 2011 10:29:44
Folgendes Problem: In einem bash-Skript sollen Eingabezeilen verarbeitet werden. Die Eingabezeilen sind aber nicht mit Newlines beendet, sondern mit Nullbytes (ASCII-NUL, \0). Außerdem können Newlines und anderer Whitespace korrekter und zu erhaltender Inhalt der Zeilen sein.

Das Whitespace-Problem ist schnell gelöst: Einfach die shellinterne Variable IFS (internal field separator) setzen. Aber wie liest man NULL-terminierte Zeilen ein?

Dieses sehr informative, aber englische Blogeintrag zum Thema bash und read bietet die Lösung. Das Shell-Builtin read versteht unter anderem die Option "-d <delim>". Darüber kann man den Trenner für Eingabezeilen festlegen. Auch Nullbytes kann man festlegen - wenn man weiß, wie, denn der erste Anlauf '\0' funktioniert nicht!

Korrekte Lösung: Einfach einen Leerstring als Delimiter übergeben.

read -d '' LINE

Im Zusammenhang sähe eine Lösung dann so aus:

# Ursprünglichen IFS sichern
OLD_IFS="$IFS"

# IFS leeren, damit Whitespace nicht verändert wird
IFS=""

find . -print0 | while read -d '' LINE; do
# In LINE befindet sich nun eine unveränderte Ausgabezeile von find(1)
done

#Alten IFS restaurieren
IFS="$OLD_IFS"

ich hoffe, das hilft mal irgendwem weiter.

Jochen

Shellscripting: Unter welchem Desktop laufe ich?

LinuxPosted by Jochen Sun, May 02, 2010 18:00:56
Hi, Welt da draußen,

die ersten Prototypen für gsm-ussd-GUIs mit Hilfe von kdialog bzw. zenity stehen bereits. Die möchte ich nun ganz gerne in ein einziges Skript packen und dann dynamisch die passende Variante, je nach Desktop Environment (KDE/GNOME), verwenden. Stellt sich nur eine Frage:

Wie stelle ich im (Shell-)Skript fest, unter welchem Desktop es läuft?

Grundsätzlich kann man ja $DISPLAY befragen, ob man grundsätzlich erst mal unter X unterwegs ist. Meine bisherigen Tests mit Umgebungsvariablen waren bestenfalls durchwachsen. Die beschriebene Vorgehensweise in diesem Thread finde ich dagegen etwas overengineered. Eigentlich hätte ich etwas wie XDG_DESKTOP_SESSION="gnome|kde|lxde|xfce4|whatever" erwartet, aber so logisch ist es nun leider nicht...

Hat irgendjemand eine bessere Idee da draußen? EDIT: Ja, hat jemand! Vielleicht hätte ich von vorneherein noch etwas mehr Energie ins Suchen stecken sollen...

In diesem archivierten Mailinglistenbeitrag sind die zwei nötigen Umgebungsvariablen aufgeführt: KDE_FULL_SESSION und GNOME_DESKTOP_SESSION_ID. Damit komme ich erstmal weiter - aber so ein XDG_DESKTOP_SESSION hätte ich um Längen einfacher und flexibler gefunden. Was mache ich bei LXDE? XFCE4?

Grüße,
Jochen

knetworkmanager & "Netzwerkverwaltung deaktiviert"

LinuxPosted by Jochen Thu, April 29, 2010 09:36:38
Vielleicht geschieht's mir ja recht, man soll ja Beta-Versionen/Release Candidates nicht produktiv einsetzen. Die Verlockung in der Testphase war aber zu groß, so dass ich nach kurzer Zeit auf Kubuntu 10.04 umgestiegen bin. Allerdings hat sich der NetworkManager bereits zum zweiten Mal beim Booten verschluckt...

Symptom: knetworkmanager zeigt im Menu keinerlei auswählbare Punkte, sondern nur den inaktiven Punkt "Netzwerkverwaltung deaktiviert" an. NetworkManager selbst läuft aber einwandfrei.

Ursache: Der NetworkManager ist der Meinung, er soll sich nicht um's Netzwerk kümmern. Dies schließt er aus dem Inhalt der Datei /var/lib/NetworkManager/NetworkManager.state. Deren Inhalt sieht aus wie eine Windows-INI-Datei:

[main]
NetworkingEnabled=false
WirelessEnabled=true
WWANEnabled=false

Lösung: Der Wert "false" für "NetworkingEnabled" muss auf "true" gesetzt werden. Die korrekte Fassung sieht also so aus:

[main]
NetworkingEnabled=true
WirelessEnabled=true
WWANEnabled=false

Wenn diese Änderung eingepflegt ist, noch den NetworkManager neu starten:

$ sudo service network-manager restart

Daraufhin sollte der knetworkmanager kurz den Kontakt mit dem NetworkManager verlieren und wieder herstellen und danach wie gewohnt funktionieren.

Da ich das jetzt schon zum zweiten Male googeln musste, hier nun noch mal zum leichteren Wiederauffinden verewigt. Ich hoffe, es nützt auch jemand anderem!

Grüße,
Jochen

Zenity & Markup - Bug oder Feature?

LinuxPosted by Jochen Wed, April 28, 2010 12:36:57
Beim Basteln mit zenity kam mir folgende Fehlermeldung unter:

(zenity:10859): Gtk-WARNING **: Failed to set text from markup due to error parsing markup: Error on line 2 char 25: Element 'markup' was closed, but the currently open element is 'pin'

Ahhhh ja. B^)

Die Meldung dreht sich also um (XML? HTML?) Markup, wobei das Element "pin" geöffnet ist, aber noch nicht geschlossen wurde, während das übergeordnete Element schon geschlossen werden soll. Hmm... "pin"? Das sieht aus, als hätte es etwas mit meinem "gsm-ussd"-Skript zu tun, nur dass ich da nirgends mit irgendeinem Markup arbeite. Außerdem sollte der zenity-Aufruf auch nirgends XML oder so übergeben bekommen! Und dann schaute ich mir die Meldung an, die zenity darstellen sollte:

SIM card is locked, but no PIN to unlock given.
Use "-p <pin>"!

*facepalm*

OK, zenity ist also der Meinung, dass es meinen Text als Markup interpretieren muss und stolpert dabei über "pin" in spitzen Klammern. Eine kleine Google-Recherche weiter findet man dann auch einen Thread im Ubuntu-Forum zum Thema zenity & Markup, der auch ein bisschen die Möglichkeiten wie fetten oder kursiven Text anreißt.

Nun gut, zenity funktioniert eben so. Aber warum ist das nirgends dokumentiert?!? Weder in der man page noch in der Online-Dokumentation zu zenity findet man diese Information. Ärgerlich, wenn man da erst mal Zeit und Energie aufwenden muss, um den Fehler zu verstehen, statt beim ersten Einlesen in das Tool einen kleinen Hinweis dazu zu bekommen...