No advertising, no support, no bug fixes, payment in advance.
— AT&T Unix Policy (1984)

Router Advertisments in OpenBSD

Seit OpenBSD 5.6 hat sich die Konfiguration für IPv6 Router Advertisements geändert.

Bisher hat man über sysctl ein globales Flag eingeschaltet, das die automatische Konfiguration von IPv6 Adressen erlaubt. Das Flag enabled die Option aber automatisch für alle Interfaces. Deshalb wurde es entfernt und durch ein Flag in ifconfig ersetzt.

1
2
$ sysctl net.inet6.ip6.accept_rtadv=1
sysctl: fourth level name accept_rtadv in net.inet6.ip6.accept_rtadv is invalid

Die neue Konfiguration wird nun in /etc/hostname.em0 angezogen.

1
2
3
$ cat hostname.em0
dhcp
inet6 autoconf

Ist also pro Interface einzeln konfigurierbar. Bin darüber gestolpert, da mir das beim (etwas dürftig formulierten) Changelog nicht aufgefallen ist. Nach etwas Mailinglisten stöbern hier und da konnt ichs aber finden.

Danach noch ein sh /etc/netstart em0 und IPv6 geht wieder.

SMTPS OpenSMTPD

Mein Mailprovider ist mittlerweile ein halbes Jahr neomailbox.net. Seit einiger Zeit hatte ich aber Probleme beim Einliefern von Mails zum SMTP Server. Mutt resettet beim SMTP mit CRAM-MD5 über SSL immer wieder die Verbindung. Kein Einliefern möglich.

Eigentlich ist die .muttrc ziemlich straight-forward was das betrifft

1
2
3
4
5
set smtp_url="smtp://user@neomailbox.net"
set smtp_pass="PW"
set ssl_starttls = yes
set smtp_authenticators = "cram-md5"
set ssl_force_tls = yes

Debugging

Also erstmal openssl angeworfen um damit zu schauen was die Serverseite so erzählt. Zuvor aber Username und Password in BASE64 encodiert vorbereiten:

1
2
perl -MMIME::Base64 -e 'print encode_base64("passwort");'
perl -MMIME::Base64 -e 'print encode_base64("username");'

Dann Verbindung zum SMTPS aufbauen und bisschen Tippern.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
openssl s_client -connect 5.148.176.58:465
---
220 s3.neomailbox.net ESMTP
ehlo noc.n0q.org
250-s3.neomailbox.net Hello noc.n0q.org [127.0.0.1]
250-SIZE 52428800
250-PIPELINING
250-AUTH CRAM-MD5 PLAIN LOGIN
250-STARTTLS
250 HELP
AUTH LOGIN
334 VXNlcm5hbWU6
XYZABCDEFGHIJ
334 UGFzc3dvcmQ6
ABCDEFGHIJKLMNO
235 Authentication succeeded
MAIL FROM:example@example.org
250 OK
RCPT TO:example@example.org
RENEGOTIATING
depth=1 C = BE, O = GlobalSign nv-sa, CN = AlphaSSL CA - SHA256 - G2
verify error:num=20:unable to get local issuer certificate
verify return:0

Ich bin mir bis jetzt nicht sicher ob das renegotiaten nach MAIL FROM: normal ist. Danach war jedenfalls auch meine Plaintext-Session vorbei. Fand ich komisch. Ich dachte auch ob es vielleicht am LibreSSL des OpenBSD auf der Kiste liegt, die ich benutze. Ein Test mit Debian bewies aber dann das Gegenteil.

OpenSMTP als lokaler MTA

So konnte das ja auch nicht bleiben. Mails verschicken können wär schon schön. Da es sowieso ein OpenBSD ist, auf der mein mutt läuft war der OpenSMTPD schon da.

Was folgt ist eine kurze Anleitung, alle Mails an einen remote SMTP Server mit Authentifizierung weiterzuleiten.

Das secrets File erstellen

1
2
3
4
$ echo "neo user:pw" > /etc/mail/secrets 
$ chown root:_smtpd /etc/mail/secrets 
$ chmod 640 /etc/mail/secrets 
$ makemap /etc/mail/secrets

und die smtpd.conf wie folgt anpassen:

1
2
3
4
5
listen on lo0
table aliases db:/etc/mail/aliases.db
table secrets db:/etc/mail/secrets.db
accept for local alias <aliases> deliver to mbox
accept for any relay via secure+auth://neo@neomailbox.net:465 auth <secrets>

Die .muttrc auf localhost umbiegen

1
set smtp_url="smtp://localhost:25"

Das hat jetzt nicht nur den Vorteil, dass ich wieder Mails versenden kann. Mir gefällt auch, dass ich jetzt bei eventualler nicht-Verfügbarkeit des Provider-SMTPs eine queuende Instanz habe. Ausserdem Logfiles in denen ich wirklich sehen kann wann eine Mail mein System verlassen hat. Negativ: Eine Komponente mehr die potentiell kaputt gehen kann.

Von gebundenen Ports die nicht hören wollen

Ich komme immer mal wieder in die Verlegenheit in der Arbeit solo zu benutzen. Um doppelte Läufe von Cronjobs zu verhindern beispielsweise.

Der betroffene Cronjob konnte nun aber schon mehrere Stunden nicht mehr ausgeführt werden.

1
2
./solo -port=3005 ./script.sh
solo(3005): Address already in use

Scheinbar läuft dieser Prozess noch, vermutlich ist er der eigentliche Prozess aber auf irgendeine Weise gestorben. Also machte ich mich auf die Suche nach dem Prozess, der den Port blockiert.

1
2
3
4
5
6
7
8
$ netstat -tapn | grep 3005 
$ lsof -Pnl +M -i4 | grep 3005
$ fuser 3005/tcp
$ lsof -i :3005
$ socklist | grep 3005
$ cat /proc/net/tcp 
$ cat /proc/net/udp 
$ ss -pl |grep 3005

Man sieht schon, ich hab “ein bisschen was” versucht um das herauszubekommen. Ich habe schon an solo an sich gezweifelt, und danach angefangen zu verifizieren, ob der Port wirklich in Verwendung ist.

1
2
$ netcat -lvp 3005
retrying local 0.0.0.0:3005 : Address already in use

Ich habe auch mit strace mitgehört, was Perl da tut.

1
2
3
$ strace -o /tmp/foo ./solo -port=3005 "echo anfang ; sleep 5 ; echo ende"
[...]
> bind(3, {sa_family=AF_INET, sin_port=htons(3005), sin_addr=inet_addr("127.0.0.1")}, 16) = 0

Okay. Der Port wird verwendet. Bis mir der Unterschied zwischen bind() und listen() auf OS-Ebene wirklich klar wurde verging eine peinlich lange Zeit. Was bedeutet das innerhalb des Betriebssystems eigentlich. Ich kann diesen Port/Socket mit den oben genannten Tools garnicht finden. Weil er lediglich “gebunden” ist aber nicht “hört”, nicht für andere zur Kommunikation bereitsteht.

Das war auch so dieser Moment, in dem ich mir dachte dass mir ein paar Uni-Vorträge in Betriebssystem-Lehre wohl nicht geschadet hätten.

Die einzige Weise mit der ich den Prozess finden konnte war mit einem Hinweis aus dem Netz. Bei nicht erkennbarem Protokoll werden in lsof mit can't identify protocol gekennzeichnet.

1
2
$ lsof | grep identify
2727            root    3u     sock                0,6      0t0   41804186 can't identify protocol

Das war aber auch schon das einzige was mir einfiel. Problem hatte sich dann für mich erledigt. Prozess beseitigt. Funktionierte wieder. Sollte jemand aber einen Hint haben, wie man gezielter danach suchen kann, bitte her damit!

Hartes Discard Protokoll

Ich habe verloren. Als ich gestern das OpenBSD unter devnull-as-a-service.com upgegraded habe, musste ich die Kiste durchbooten.

Nachdem ich das Discard Protokoll über den OpenBSD inetd auf Port 9 aktiviert habe, haben ein paar Leute dort dauerhaft Connections geöffnet.

Ich dachte, mal sehen wer längern kann. Client oder Server. Stellte sich heraus: die Clients.

Aber da ich ein guter Verlierer sein kann, Respekt und Gratz.

OpenBSD IPv6

Was ich ja schon immer komisch fand ist, dass die Dokumentation oder auch uch How-Tos im Netz was das Thema OpenBSD und IPv6 angeht echt ultra duerftig ist.

Da ich meine Debian VM auf der ich weechat, mutt, jabber usw laufen habe vor nem Monat ebenfalls auf OpenBSD umgezogen hab, stellte sich mir das Problem schon wieder.

IPv6 mit Router Adverisement (rtadv)

Am komfortablesten ist natuerlich einfach das rtadv den Hosting Providers herzunehmen. In meinem Fall rootbsd.net haben aber nur kleine Anleitungen fuer FreeBSD.

Um den IP Stack auf IPv6 Advertisements antworten zu lassen muss nur /etc/sysctl.conf editiert werden mit

net.inet6.ip6.accept_rtadv=1

Einmal rebooten oder per Hand sysctl net.inet6.ip6.accept_rtadv=1 ausfuehren.

1
2
3
4
5
6
7
8
9
10
11
$ ifconfig
em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:16:3e:2c:4a:41
        priority: 0
        groups: egress
        media: Ethernet autoselect (1000baseT full-duplex)
        status: active
        inet6 fe80::216:3eff:fe2c:4a41%em0 prefixlen 64 scopeid 0x1
        inet 12.34.56.78 netmask 0xffffff80 broadcast 185.34.0.255
        inet6 2a00:d1e0:1000:3100:dead:beef:4a41 prefixlen 64 autoconf pltime 604729 vltime 2591929
        inet6 2a00:d1e0:1000:3100:dead:beef:df24 prefixlen 64 autoconf autoconfprivacy pltime 18185 vltime 537125

IPv6 mit statischer IP

Wenn der Provider kein Router Advertisment anbietet, aber dafür eine IP assigned und auf diese IP ein eigenens Netz für einen routet.

Konfigurieren der Adressen:

1
2
3
4
5
6
$ vi /etc/hostname.em0
inet 213.95.21.200 255.255.255.0 NONE
inet6 alias 2001:780:3:5::122 64   # Transit IP
inet6 alias 2001:780:132::1 48     # IP aus eigenem Netz
inet6 alias 2001:780:132::2 48     # IP aus eigenem Netz
inet6 alias 2001:780:132::3 48     # IP aus eigenem Netz

Konfiguration des Gateways

1
2
3
vi /etc/mygate 
213.95.21.1
2001:780:3:5::1

Und danach Interface reloaden mit sh /etc/netstart em0.

OpenBSD httpd

Reyk Floeter hat zuletzt begonnen seinen relayd zu forken und einen minimalistischen Webserver daraus zu bauen. Langfristig soll httpd in OpenBSD den erst kürzlich in Base gewanderten nginx ersetzen.

Die Hintergründe dazu kann man gut im BSDNOW Podcast 053 nachhören. Zuerst denkt man so “Was? Noch ein HTTP Daemon?”. Zusammengefasst soll der neue httpd aber genau das werden (und vor allem bleiben) wie nginx angefangen hat. Plain, Free, minimalistisch, einfach. So wurden auch schon mehrere Diffs/Features vom Entwickler abgelehnt.

Konfiguration OpenBSD gemäß sehr straight forward. pf/relayd like. Hab mir nen 5.6 Snapshot vom Mirror meiner Wahl besorgt und das Teil mal ausprobiert.

Nach etwas herumprobieren: grinsen. Comic Sans in den default Error Messages.

Bin mir nicht sicher ob das so bleibt. Die Config Parameter sind wie bei OpenBSD Software zu erwarten gut dokumentiert und eingängig.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
prefork 5

server "default" {
  listen on em0 port 80
  root /var/www/htdocs/default
  directory
}

server "default" {
        listen on em0 port 80
        log syslog
        log access default-access.log
        directory auto index
        connection timeout 30
        connection max requests 120
}

server "httpd1.noqqe.de" {
        listen on 192.168.1.14 port 80
        root "/htdocs/httpd1/"
        log syslog
        directory auto index
}

server "httpd2.noqqe.de" {
        listen on 192.168.1.14 port 80
        root "/htdocs/httpd2/"
        log syslog
        directory auto index
        connection timeout 3600
}

Noch ist das gute Stück nicht Feautre-Complete bzw. Production-Ready. Dinge die noch fehlen, aber kommen werden ist zum Beispiel Basic HTTP Auth. SSL und ein bisschen mit beeswithmachineguns Performance austesten hab ich bisher noch nicht gemacht. curlfor-loop mit time zum Ausprobieren kann man kaum Performance Test nennen ;) Demnächst dann vielleicht.

httpd wird er ab 5.6 in Base mit nginx koexistieren. Portable Version ist ebenfalls geplant. Freu mich drauf.

MacBook

Nachdem ich die letzte Zeit viele Betriebssysteme auf dem Thinkpad ausprobiert haben (FreeBSD, ArchLinux, ElementaryOS, OpenBSD) und nichts mich wirklich befriedigt hat, bin ich wieder zu Debian zurück.

Einige Zeit später bekam ich in der Arbeit in MacBook. Fand wieder gefallen daran. Kaufte MacBook Pro (14. Generation).

Dinge, dich ich bei beiden MacBooks als erstes verändert habe:

  • Dock auf die linke Seite konfiguriert (in der Breite hab ich mehr Platz als in der Länge)
  • Key Repeat und Delay until Repeat Rate für das Keyboard bis zum Anschlag verkürzt. Aber darüber hab ich bereits geflamed.
  • FileVault aktivieren.
  • Natural Scrolling deaktivieren (srsly, was soll das?)
  • German - Eliminate Dead Keys Keyboard Layout installieren
  • Zwischen Fenstern der selben Applikation wechseln mit Apfel + >
  • caffeeine installieren (caffeinate für die Kommandozeile)
  • Homebrew/MacPorts installieren
  • xquartz installieren
  • Hässlichen Terminal-Beep in iTerm2 oder TerminalApp deaktivieren
  • locate aktivieren

Noch weitere Tipps, anyone?

How to do simple and efficient image crawling

Im Rahmen von nichtparasoup ergab es sich, dass wir uns Gedanken über crawling machen mussten.

Bei nichtparasoup sollen zufällig Bilder aus dem Netz wiedergegeben werden um wenn möglich den optimalen Unterhaltungswert für den “Zuschauer” darzustellen. Dabei galt es vier Probleme zu lösen:

  • Möglichst aktuelle Bilder (kein alter Schrott)
  • Niemals ohne Content dastehen
  • Keine Duplicates
  • Möglichst effizientes Crawling

Wie also diese Kriterien am Besten vereinen? Bei allen Quellen die benutzt werden gibt es eine Art “paging”. Also eine fixe Anzahl von Bildern, die pro Request aus der Quelle ausgespuckt werden.

1. Ein Buch lesen

Wir begannen, die Seiten einfach von Anfang bis Ende durchzuscrollen. Seite merken. Wenn alle Bilder gesehen wurden, an gemerkter Stelle weitermachen. Effizient. Aber neuer Content wurde damit komplett ignoriert.

2. Yo Dawg, i heard you like HTTP-GETs

Um neuen Content mitzubekommen, haben wir nach dem ersten Versuch, die gerade durchsuchte Quelle jedes mal wenn wir Bilder brauchten von vorne durchzusuchen. Alle Bilder wurden gleichzeitig zu zwei Listen hinzugefügt. Zur ImageMap und zu einer Blacklist. Die Blacklist hatte den Charme, dass wir ausschliesslich Bilder in die ImageMap aufnahmen, die noch nicht auf der Blacklist waren. Gab es also auf der ersten Seite (neueste Einträge) nicht genügend Bilder um die ImageMap zu füllen, ging der Crawlvorgang so lange weiter, bis man auf unbekannte Bilder stößt. Diese befanden sich jedoch meistens am Ende.

Dem Erfahrenen-Internet-Cralwer wird aufgefallen sein, dass das nicht wirklich effizient ist. Umso länger die nichtparasoup-Instanz läuft, umso größer wird der Gap zwischen dem “neuen” Content und der letzten bekannten Seite. Ineffizient.

3. Lesezeichen

Eine erweiterte Version der zweiten Methodik war es, bei jeden Crawlvorgang die erste Seite zu Crawlen und danach an der letzten bekannten Stelle im “Buch-index” zu springen und dort weiter nach unbekannten Bildern zu suchen.

Aber was ist, wenn die Instanz lange nicht besucht wird? Wenn es auf den Index-Seiten 2,3,4,5,6 bereits neuen Content gibt den wir noch garnicht kennen? Wie können wir wissen bis an welche Stelle neuer Content ist?

4. Short-Term-Memory-Loss

Die Lesezeichen Methodik hat ganz gut funktioniert, bis auf die Schwäche des neuen Contents auf den Seiten 2,3,4,5,6.

Nachfolgendes, kann man sich wie einen Rentner ohne Lesezeichen vorstellen. Er versucht sich die Seite, auf der er im Buch stehengeblieben ist zu merken. “Wo war ich nochmal stehen geblieben?” … “Fang ich das Buch halt nochmal von vorne an.”

Um auch neuen Content gecrawlt zu bekommen, wird das Lesezeichen, welches wir bei jedem Durchlauf pro Quelle setzen, alle 3 Stunden “vergessen”. Alles fängt wieder von vorne an. Wir müssen nicht zu viel Bookkeeping betreiben und verballern auch nicht unendlich viele Requests. Die Implementation war relativ einfach.

Ich bin mir ziemlich sicher, dass es hier akademische Beleuchtungen noch und nöcher gibt, schlaue Menschen bei allen Möglichen Suchmaschinen sich Köpfe zerbrochen haben und entsprechende Papers veröffentlicht haben. Für unsere Zwecke eignet sich diese Vorgehensweise aber sehr gut. Zumindest was die Erfahrungswerte der letzten 3 Monate angeht. Für bessere Vorschläge sind wir aber sehr gern zu haben.

The Phoenix Project

Im Urlaub laß ich ein wunderbares Buch. The Phoenix Project.

Das eBook handelt von Bill Parmer der von heute auf morgen zum Leiter der IT des ~4 Milliarden Dollar Unternehmens befördert wird, in dem er arbeitet.

Wer ITIL, ISO20000 oder ISO27001 kennt, kennt einige Konzepte die hinter Opetations und Development stecken. Das Buch verpackt all die schönen Best Practices und Vorgehensweisen zur Beherschung moderner IT Abteilungen in einen Roman. Eine nerdige, lustige und teils schockierende Story, in der Bill die völlig marode IT im Trial and Error Verfahren trotz immer neuer Rückschläge wieder auf Kurs bringt.

Ich denke es ist großartige Alternative den ganzen trockenen Content obiger Konzepte zu ersparen und trotzdem vermittelt zu bekommen um was es im Dev/Ops Bereich geht.

Jeder der was mit IT zu tun hat: Lesen. Oder gebt es euren Chefs, damit die es lesen.

Mehr BSD, Bye Uberspace

Ab und an passiert es, dass Dinge die einfach funktionieren anfangen mich zu langweilen. So geschehen mit Uberspace. Das CentOS, der Apache2.2, die Sache mit den Domains.

Im Grunde habe ich die 3 Dienste, die ich bei Uberspace nutze (Webserver für Blog, Mail, Domains) nun zu anderen Dienstleistern migriert.

Blog Webserver

Der erste “Dienstleister” bin ich gewissermaßen selbst. Die 1HE Dell Maschine die ich seit einiger Zeit bei meinem alten Arbeitgeber mit OpenBSD betreibe, hostet mit nginx den Blog. Selbige Kiste delivered auch devnull-as-a-service.com und coffeestat.org. Warum also eine extra Lösung.

Mails

Bei Uberspace hatte ich die Mglichkeit die Mails direkt von Qmail über Maildrop umzusortieren und dort meine Tools zu platzieren.

Mein neuer Mailprovider neomailbox.net hat seinen Firmensitz auf den Seychellen, Server in der Schweiz und setzt ebenfalls auf OpenBSD als OS. Nicht weil ich ernsthaft glaube, das ich das bräuchte, sondern weils mir gefällt.

Mit dem Wechsel ändert sich aber die Architektur meines Setups. Statt direkt am IMAP Server arbeiten zu können bin ich nun nur noch Konsument des IMAP Services. Blöd für maildrop-Regeln und Spamfiltering mit bogofilter.

Gerade beim Abschied von Bogofilter tat ich mich schwer, weils so gut und einfach ist. Aber dann entdeckte ich imapfilter.

imapfilter ist primär dazu gedacht Mails zwischen einem oder mehrere IMAP Accounts zu verschieben. Meine maildrop Regeln sind sehr leicht umgesetzt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
neomailbox = IMAP {
    server = 'neomailbox.net',
    username = 'user',
    password = 'pw',
    ssl = 'ssl3',
}

-- get set of mails from the last day
res = neomailbox.INBOX:is_newer(1)

-- move techmails to Tech/
tech = res:contain_to('tech@openbsd.org') +
       res:contain_cc('tech@openbsd.org') +
       res:contain_from('Cron Daemon <root@') +
       res:contain_from('Charlie Root <root@o0.n0q.org>') +
       res:contain_from('root@z0idberg.') +
       res:contain_from('noc.n0q.org')
tech:move_messages(neomailbox.Tech)

-- spam by vipul razor to Spam/ (offered by neomailbox.net)
-- header: X-SA-Status: Yes
spamvipul = res:contain_field('X-SA-Status', 'Yes')
spamvipul:move_messages(neomailbox.Spam)

Mit den Ergebnissen von vipul razor Antispam war ich aber nicht so 100%ig zufrieden, weshalb ich anfing zu googeln und fand was ich suchte.

Imapfilter piped jede Mail des letzten Tages zu dem lokal laufenden bogofilter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- bogofilter spam mails to Spam
res = neomailbox.INBOX:is_newer(1)
spam = Set {}
unsure = Set {}
  for _, mesg in ipairs(res) do
        mbox, uid = unpack(mesg)
        text = mbox[uid]:fetch_message()
        -- subject = mbox[uid]:fetch_field('subject')
        -- print(subject)
        flag = pipe_to('/usr/bin/bogofilter', text)
        if (flag == 0) then
          table.insert(spam, mesg)
        elseif (flag == 2) then
          table.insert(unsure, mesg)
        end
  end
neomailbox['INBOX']:move_messages(neomailbox['Spam'], spam)

H00ray!

Domains

Relativ unspektakulär, habe ich meine Domains zu inwx.de umgezogen. Preise und Webinterface sind okay. Und falls ich mal Lust habe eine Art DynDNS selbst zu bauen haben die auch gleich eine API.

Alles in allem kann ich mit dem neuen Setup gut Leben. Mehr OpenBSD, weniger Linux.