Samstag, 30. Juni 2018

Windows hat jetzt ssh

Seit vielen Jahren gibt es eine open-ssh Portierung für Windows im Entwicklungs/Beta/Schatten Dasein. Seit der Windows 10 Version 1803 (in 1709 noch als Beta) ist es jetzt offiziell als Feature enthalten und der Client sogar per Default installiert. Die interessante Frage:

Ersetzt das putty?

Wäre zumindest mein Ziel, dann muss man in Zukunft nichts nachinstallieren. Einfach mal versuchen:
Windows + r Taste zum Ausführen drücken und den Befehl eintippen:
ssh username@hostname-oder-IP-Adresse
Es kommt die Abfrage nach dem Passwort bzw. beim ersten Mal vornweg die typische Frage nach der Authentizität des Hostes. Schon ist die Terminalkonsole offen.

Verbindung mit ssh Key

Die OpenSSH Portierung stellt auch einige Tools wie ssh-keygen zur Verfügung. Wie üblich kann man sich einen Key Pärchen im Homedirectory im Pfad .ssh erzeugen lassen. Der Befehl
ssh-keygen -t rsa
schlägt als Verzeichnis vor: C:\Users\name/.ssh/id_rsa
Was natürlich bezüglich der Pfade irgendwie lustig aussieht: Windows trifft Linux.

Alle ssh Befehle mit Bezug auf die Benutzerumgebung müssen ein einem cmd Fenster in der Benutzerumgebung ausgeführt werden!
Geht ganz einfach mit Windows + r Taste + cmd
Die Verwendung einer Powershellkonsole ist wegen der Zeichenkodierung nicht zu empfehlen (siehe weiter unten).

Man kann, wie üblich, den Public Key auf andere System übertragen und sich dort ohne weitere Passworteingabe einloggen und Befehle ausführen (Blog Link zu verwandtem Thema).
Dazu unbedingt die Anmeldung am Windows entsprechend absichern!

Mit SCP Dateien kopieren

Eigentlich ist dies die Funktion von WinSCP &Co. Aber Windows bringt jetzt zumindest Zugriff über die Kommandozeile mit. Und wenn das mit dem Key ohne Passwort funktioniert - warum dann zweimal anmelden?
Kurz und knapp der Syntax um eine Datei zwischen den HomeDirs zu kopieren.
Wie immer: Quelle -> Ziel
scp Dateiname username@hostname:
scp username@hostname:Dateiname .
Während Remote als Ziel der Pfad entfallen kann (HomeDir) muss bei lokal als Ziel mindestens der "." (HomeDir) stehen.

Eigenheiten

Die Anführungszeichen!

  • Remote Befehle müssen in die "Doppelten" gekapselt werden. Bei Linux gehen dort auch einfach 'Remote Befehl'.

Das Beispiel erzeugt lokal eine Datei mit dem Inhalt der Ausgabe des Remote Befehls:
ssh username@hostname "ls -l" >InhaltUserHomeDir.txt

Tools fehlen oder sind unvollständig!

Ein paar Details und Workarounds findet man weiter hinten in diesem Artikel.

Die Antwort

Ich denke putty kann insgesamt mehr, aber wer genau das braucht, was ich hier beschrieben habe, kommt mit dem neuen ssh Client in Windows 10 (ab Version 1083) gut klar. Und die folgende Menüleiste finde ich komfortabler als putty.

Ein paar Tipps

Menüleiste mit den fertigen Verbindungen

Basis ist ein neuer Ordner mit Verknüpfungen darin.
Tipp: Wer ein MS Konto benutzt hat OneDrive, dann am Besten dort und es ist überall verfügbar!
Beispiel: Ordnername "ssh Hosts"
Rechtsklick auf Laufwerk oder Desktop / Neu / Ordner

in dem Ordner Rechtsklick / Neu /Verknüpfung

Rechtsklick Taskleiste / Neue Symbolleiste / Ordner auswählen





Zwei Angaben bei der Verknüpfung: 1 Fenster Befehl und 2. Fenster "Menüpunktname"
Nach dem Klick auf Neue Symbolleiste navigiert man zu dem gerade angelegten Ordner.
Fertiges ssh Menü
Beispiel für Verknüpfungsziele

  • ssh username@192.168.1.1
  • ssh pi@raspberrypi
  • cmd
Wie man das noch etwas mit Powershell kombinieren kann zeige ich in diesem Artikel.

Putty Keys verwenden

Wenn man schon mit einem Putty Key gearbeitet hat, kann man den weiter verwenden. Wobei es bei eigenen Maschinen auch nicht schlimm und am Ende einfacher ist, einen Neuen zu erzeugen.
Man braucht dazu puttygen. In dem grafischen Tool wird mit Load das existierende ppk File mit dem Key geladen.
Den public Key kann man direkt mit der sichtbaren Schaltfläche exportieren, er muss aber dann noch weiter bearbeitet werden, deshalb hier irgendeinen temporären Namen (c:\users\Name\ppkPub.txt) verwenden und diesen mit Pfadangabe merken!
Den private Key müssen wir exportieren: Conversions / Export OpenSSH Key
Hier gleich den richtigen Ort und Namen angeben %userprofile%\.ssh\id_rsa
Dabei eventuell vorher den Pfad %userprofile%\.ssh erzeugen.
Jetzt unbedingt ein cmd Fenster und nicht Powershell öffnen! Der Public Key hat ein falsches Text Format (mehrzeilig). Das Tool ssh-keygen kann diesen umwandeln und gleich an die richtige Stelle schreiben:
ssh-keygen -i -f c:\users\Name\ppkPub.txt >%userprofile%\.ssh\id_rsa.pub

Wie und wo installieren?

Wer jetzt Stelle sucht wo es aktiviert und installiert wird, wird feststellen: Die Sache wird auch nicht übersichtlicher! Je nach dem wie man die Windows Suche benutzt, findet man jetzt:
  • Apps & Features - dort findet man es unter dem Punkt Optionale Features verwalten.
  • Programme hinzufügen oder entfernen - führt letztlich zu Apps & Features
  • Optionale Features - führt direkt zum Punkt
  • Windows-Features aktivieren oder deaktivieren - ist etwas völlig anderes. Obwohl man hier durchaus Komponenten aus Optionale Features findet.
  • Systemsteuerung / Programm deinstallieren oder Ändern hat zwar Windows-Features als Unterpunkt aber die Programme die hier gelistet werden müssen nicht mit denen übereinstimmen die man unter Apps & Features findet.
Powershell ist immer eine gute Lösung, wenn man die Installation exakt beschreiben will. Auf docs.microsoft.com findet man unter dem Stichwort WindowsCapability ein paar cmdlets die aus der dism Verwaltung kommen. Deswegen ist der Syntax etwas "speziell" und man muss schon die Abfrage als Administrator ausführen!
Hinweis: Damit das Installationsthema nicht so einfach wird:
  • Get-WindowsOptionalFeature liefert Windows-Features, 
  • Get-Package liefert installierte Programme, 
  • Get-AppxPackage liefert "vorinstallierte Programme".
Auf dem Server gibt es ein separates Set an CMD-lets z.B. Get-WindowsFeature, Install-WindowsFeature...

Einschränkungen Windows ssh Client

Leider existiert das Tool ssh-copy-id nicht. Deswegen muss man den Key mit ein paar Linux Befehlen übertragen. Ich habe dazu einen extra Artikel verfasst.

Das Tool ssh-keygen kann die known_hosts Datei nicht verwalten.
Update: Aktuell mit der Windows Version 1809 funktioniert es wie gewohnt.
Bisher wurde ein Versuch spartanisch quittiert:
ssh-keygen -R 192.168.178.82
Updating known_hosts is not supported in Windows yet.
Die Datei .ssh\known_hosts ist UTF-8 und mit CR LF kodiert. Man kann sie mit einem Texteditor einfach editieren und die fragliche Zeile löschen. Oder mit dem cat und grep Pendant von Windows geht es mit diesem Zweizeiler:
type .ssh\known_hosts > .ssh\known_hosts.org
findstr /V "192.168.178.82" .ssh\known_hosts.org > .ssh\known_hosts

Windows OpenSSH Server installieren

Edit: Ich habe hier einen Artikel mit einer ergänzenden Anleitung zur Installation des ssh Servers erstellt.

Das machen wir einfach alles mit Powershell.
Windows 10
Der Add Befehl kann hier nicht mit Wildcards umgehen.
Add-WindowsCapability -Online -Name  OpenSSH.Server~~~~0.0.1.0
Jetzt prüfen ob erfolgreich installiert wurde:
Get-WindowsCapability -Online | where name -match 'ssh'
Man kann auch die installierten Dienste prüfen, sie laufen aber noch nicht!
Get-Service -Name *ssh*
Also Dienste auf Automatic setzen und starten:
Get-Service -Name *ssh* | Set-Service -StartupType Automatic
Get-Service -Name *ssh* | Start-Service
Jetzt kann man sofort loslegen und sich zum ssh Server verbinden, eine separate Firewallregel braucht man nicht, die ist offenbar schon eingerichtet. Ich musste nichts weiter einrichten!
Man wird über ssh zur cmd Konsole verbunden, hier kann man dann auch Powershell starten! 

Hinweis:
Die Konfiguration des Servers liegt in C:\ProgramData\ssh.
Get-ChildItem -Path 'C:\ProgramData\ssh\'
Quelle zur Installation

Windows Server
Auf dem Windows Server ist ssh erst ab der ReleaseID 1709 integriert Windows Server 2016 ist die ID 1607.
Auch auf früheren Versionen kann man die aktuelle Win32 OpenSSH Version installieren.
Achtung: für den folgenden Code (und für eine aktuelle Management Umgebung) muss Windows Management Framework 5.1 installiert sein!

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$url = 'https://github.com/PowerShell/Win32-OpenSSH/releases/latest/'
$request = [System.Net.WebRequest]::Create($url)
$request.AllowAutoRedirect=$false
$response=$request.GetResponse()
$url = $([String]$response.GetResponseHeader("Location")).Replace('tag','download') + '/OpenSSH-Win64.zip'
Invoke-WebRequest $url -OutFile openssh.zip
Expand-Archive .\openssh.zip 'C:\Program Files\'
cd 'C:\Program Files\OpenSSH-Win64\'
.\install-sshd.ps1
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
Start-Service -Name sshd
Set-Service -Name sshd -StartupType automatic

Tipp zur Anmeldung mit ssh an Windows 10

Ich melde mich mit einem Online Konto (Format user@domain) am Windows Desktop an. Windows legt intern zu diesem Online Konto eine Art "Kurznamen" an. Der ssh Server akzeptiert nur diesen kurzen Namen, eventuell kann man generell diesen Kurznamen verwenden, wenn man sich an anderen Diensten über das Netzwerk anmeldet.
Mit einer der folgenden Befehle kann man den Kurznamen ermitteln:
whoami
[Environment]::UserName
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name

Hintergrund zur Powershell Textcodierung

In der Powershell (offenbar der > Befehl) werden Text Dateien nicht in der Codierung UTF-8 sondern mit der Codierung UCS-2 LE BOM angelegt. Abhilfe in Powershell? Schwierig.
Mit Notepad++ kann man die Codierung gut anschauen.

Ein paar Tests:
  • Der Befehl innerhalb PS type .ssh/*.pub >catPub.txt erzeugt lokal eine Datei in UCS-2 LE BOM Codierung
  • innerhalb cmd eine Datei in UTF-8 Codierung
  • Der Befehl in CMD oder PS type .ssh/*.pub |ssh pi@192.168.178.80 "cat >picatpub.txt" erzeugt eine Datei in UTF-8 Codierung mit Windows CR LF
  • Wandelt man jetzt mit nano picatpub.txt durch Speichern mit alt+m in Unix LF um dann macht ein erneuter Befehl in cmd type .ssh/*.pub |ssh pi@192.168.178.80 "cat >>picatpub.txt" eine Datei in UTF-8 Codierung mit Unix LF

Das bedeutet:
  • die Übertragung über ssh / type ->  cat "filtert" die UCS-2 LE BOM Codierung aber nicht Windows CR LF.
  • Der cat Befehl unter linux ändert existierende Unix LF nicht!
  • Der type Befehl in PS mit Umleitung >> in eine existierende Datei mit UTF-8 führt zum Datensalat

Ein paar Ansätze:
Ansi ausgeben
UTF8-BOM erzeugen
Keys wieder löschen.
Winscp

Mittwoch, 27. Juni 2018

OpenWrt Router abfragen

Dieser Beitrag im Forum gab den Ansatz für eine Abfrage des OpenWrt Routers nach angemeldeten Wlan Clients. Für mich als Halbwissender war es mal wieder gar nicht einfach den kurzen Artikel umzusetzen. Deswegen hier etwas ausführlicher.

Vorbereitung des Routers

Für das cgi Script braucht man die Komponente bash auf dem Router, das ist schnell installiert.
System / Software im Feld "Download and install package:" einfach bash eintippen und Ok drücken.
Im Pfad /www/cgi-bin/ muss man jetzt eine Datei wifi-client mit folgendem Inhalt anlegen (z.B. mit WinsSCP).
Ich habe gegenüber dem Original Artikel noch die Umwandlung von Gross in Kleinbuchstaben eingebaut.
Die Zeile im Code unterhalb dem Hinweis  # Pfade anpassen je nach AP-Config!! muss man unbedingt anpassen!
Je nach dem welche Wlan Hardware verbaut ist:
  • radio0 -> phy0 
  • radio1 -> phy1
Und welche Wlans definiert sind (Beispiel):
  • wlan1 -> netdev:wlan1
  • wlan1-2 ->  netdev:wlan1-2
Die Benennung war hier nicht ganz konsequent ableitbar, also unbedingt im Pfad /sys/kernel/debug/ieee80211 nachschauen! Oder mit dem Befehl iwinfo die Liste der Wlan Namen ausgeben.
#!/bin/bash

# Decodes an URL-string
# an URL encoding has "+" instead of spaces
# and no special characters but "%HEX"
function urlDec() {
  local value=${*//+/%20}                   # replace +-spaces by %20 (hex)
  for part in ${value//%/ \\x}; do          # split at % prepend \x for printf
    printf "%b%s" "${part:0:4}" "${part:4}" # output decoded char
  done
}

# For all given query strings
# parse them an set shell variables
function setQueryVars() {
  local vars=${*//\*/%2A}                      # escape * as %2A
  for var in ${vars//&/ }; do                  # split at &
    local value=$(urlDec "${var#*=}")          # decode value after =
    value=${value//\\/\\\\}                    # change \ to \\ for later
    value=${value,,}                           # upper in lower case 
    eval "CGI_${var%=*}=\"${value//\"/\\\"}\"" # evaluate assignment
  done
}

# Execute the evaluation
# set all variables for both, POST and GET data
# $QUERY_STRING ist part of the environment and contain the part after ?
setQueryVars $QUERY_STRING $(</dev/stdin)

# Set formatting the Response to plain Text
echo Content-type: text/plain
echo
# for the Query ?dev=xxxxxx&test=yyyyyy
# Query dev= -> $CGI_dev contain value after dev=
# Query test= -> $CGI_test contain value after test= 
# Test the string contain only numbers,lower letters and :
case $CGI_dev in
        *[!0-9a-f:]*|"") echo "NOK MAC"; exit 0;;
esac

# Pfade anpassen je nach AP-Config!!
if [ -d "/sys/kernel/debug/ieee80211/phy1/netdev:wlan1/stations/$CGI_dev" ] || [ -d "/sys/kernel/debug/ieee80211/phy1/netdev:wlan1-1/stations/$CGI_dev" ] || [ -d "/sys/kernel/debug/ieee80211/phy1/netdev:wlan1-2/stations/$CGI_dev" ] || [ -d "/sys/kernel/debug/ieee80211/phy0/netdev:wlan0/stations/$CGI_dev" ]; then
       echo "connected"
else
       echo "no device"
fi
Diese Datei braucht jetzt nur noch das Ausführen (x) Recht für Alle, kann man auch gleich mit WinSCP machen.

Ohne Weiteres kann man sofort die Funktion testen:
http://wrt1900/cgi-bin/wifi-client?dev=11:22:33:aa:bb:cc
Bei bekannter MAC Adresse erscheint ein connected als Quittung, ansonsten eine entsprechende Ausgabe.

Funktion in 99_myUtils.pm

Um diese Abfrage in einem PRESENCE Device zu verwenden, braucht man noch eine kleine Perlfunktion.
sub wlan_det($) {
use LWP::UserAgent;
my ($client)= @_;
        my $ua = new LWP::UserAgent;
        my $response = $ua->get('http://wrt1900/cgi-bin/wifi-client?dev='.$client);

        unless ($response->is_success) {
                              return 99;
        }

        my $content = $response->decoded_content();

        if ($content =~ m/connected/) {
                              return 1;
        } else {
                              return 0;
        }
}
Ich musste gegenüber dem Originalbeitrag noch die Zeile mit "use LWP:.." ergänzen. Es ist eigentlich besser diese einmalig am Anfang der 99_myUtils.pm nach der Zeile
"# Enter you functions below _this_ line."
und vor allen eigenen Subs zu platzieren.
Die Definition in FHEM ist wie gewohnt:
defmod iPhone PRESENCE function {wlan_det("11:22:33:aa:bb:cc")}

Nacharbeit

Das war jetzt quick&dirty -  man kann noch
  • die Übergabe oder Definition der Router IP besser machen.
  • die Definition der abzufragenden Pfade im Router verbessern.
  • Prüfen was genau passiert wenn der Router nicht erreichbar ist (FHEM blockiert?)
  • Die Abfrage funktioniert so nur für Wifi, LAN Clients ermitteln? 

Dienstag, 19. Juni 2018

RaspberryPi mit OpenWrt/Lede

Auch für den Raspberry gibt es ein fertiges Image des Router Systems. Ob man den Raspberry wirklich als Router betreiben will sei mal dahin gestellt, als Testsystem oder DHCP Server taugt er aber allemal.
Das Image gibt es jeweils getrennt im Zweig brcm2708 im Unterpfad

  • bcm2708 -> B und B+
  • bcm2709 -> B2
  • bcm2710 -> B3

Für den B3+ muss man derzeit ein Image aus dem Snapshot Bereich nehmen.

Das gepackte Image (img.gz) muss zunächst entpackt werden (z.B. 7-Zip) und wird dann wie beim Pi üblich, mit einem passenden Programm (Win32DiskImager) auf die SD Card geschrieben.

Partition vergößern

Die resultierende Partition ist nur 256 MB groß. Wer etwas mehr auf dem Pi machen will als nur "Router" sollte die Partition von Beginn an vergrößern, online und innerhalb von OpenWrt geht das schwierig. Ich habe etwas herum probiert und bin zu folgendem Weg gekommen:

  • SD Card mit dem Kartenleser an einen vorhandenen Linux PC (z.B. Raspberry) anschließen.
  • der Stick wird als /dev/sda aktiviert und nicht gemounted
  • parted (oder parted /dev/sda) aufrufen
  • mit p(rint) vergewissern das richtige Laufwerk zu haben.

(parted) p
Model: SABRENT SD (scsi)
Disk /dev/sda: 15,8GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start   End     Size    Type     File system  Flags
 1      4194kB  25,2MB  21,0MB  primary  fat16        boot, lba
 2      29,4MB  298MB   268MB   primary  ext2

(parted)

  • resizepart 2 eingeben
  • Das neue Ende der Partition eingeben, z.B. 3GB
  • quit für exit
  • mit resize2fs muss das Filesystem angepasst werden
resize2fs /dev/sda2
resize2fs 1.43.4 (31-Jan-2017)
Die Größe des Dateisystems auf /dev/sda2 wird auf 725254 (4k) Blöcke geändert.
Das Dateisystem auf /dev/sda2 is nun 725254 (4k) Blöcke lang.


  • Mit e2fsck -f /dev/sda2 muss jetzt das Filesystem nochmal überprüft und repariert werden obwohl beim einfachen Test und auch beim Test vor der Vergrößerung alles "sauber" gemeldet wird.
e2fsck -f /dev/sda2
e2fsck 1.43.4 (31-Jan-2017)
Durchgang 1: Inodes, Blöcke und Größen werden geprüft
Inode 7, i_size ist 62963712, sollte 67178496 sein.  Reparieren? ja
Durchgang 2: Verzeichnisstruktur wird geprüft
Durchgang 3: Verzeichnisverknüpfungen werden geprüft
Durchgang 4: Referenzzähler werden überprüft
Durchgang 5: Zusammengefasste Gruppeninformation wird geprüft

/dev/sda2: ***** DATEISYSTEM WURDE VERÄNDERT *****
/dev/sda2: 1064/188416 Dateien (0.0% nicht zusammenhängend), 14433/725254 Blöcke

Erster Start

Der Router Pi läuft jetzt mit der Adresse 192.168.1.1 im Netzwerk. Um ihn für eine Konfiguration erreichbar zu machen, müssen wir dem PC zur Konfiguration einen IP Adresse z.B. 192.168.1.5 geben. Eine Variante Windows Powershell zeige ich hier.
Die Anmeldung erfolgt mit root ohne Passwort. Nicht vergessen: Als erstes ein Passwort vergeben.
Im Menü über / Network / Interfaces / Edit / das Protocol auf DHCP Client stellen, den Knopf "switch protocol" drücken und abschließend "Save & Apply" drücken.
 


Der Router bekommt jetzt eine Adresse aus dem lokalen Netzwerk und die lokale Adresse des Konfiguration PC kann zurück gestellt werden.
Damit später alle Zeiten im Log stimmen, sollte die Zeitzone auf Europe/Berlin gestellt werden.

Der Pi kann mit zusätzlichen Interfaces (USB LAN oder USB WLAN oder internes WLAN) arbeiten.
Achtung:! Mit der Version 18.06 hat sich das Verhalten verändert. Es wurde eine neue Sicherheit gegen Fehlkonfiguration eingebaut. Die führt leider dazu, das innerhalb 30 sec die Konfiguration zurückgerollt wird, wenn das Webinterface nicht erreichbar war.
Ich weiß noch nicht, wie man wirklich damit umgeht. Einzig mir bekannt bisher ist: warten bis dieses Fenster kommt, den roten Knopf drücken und erst dann die IP-Konfiguration des PC zurückstellen.

Zusätzliches Netzwerkinterface installieren

In der bisherigen Konfiguration ist das System nicht zu viel mehr zu gebrauchen als DHCP Server und um mit der Oberfläche zu spielen. Es empfiehlt sich das Software Paket usbutils zu installieren, damit hat man auf Kommandozeile den Befehl lsusb zur Verfügung und kann zumindest schauen ob der USB Adapter erkannt wird.

LAN Interface

Mit diesem Adapter hatte ich bisher gute Erfahrungen beim Pi:
I-Tec USB 2.0 Advance 10/100 Fast Ethernet LAN Network Adapter USB 2.0 auf RJ45
Er hat einen Asix AX88772B Chip. Durch die Installation des Packages kmod-usb-net-asix wird der Adapter problemlos in Betrieb genommen. Falls noch nicht geschehen muss als erstes der Knopf Update lists gedrückt werden!


Der USB Netzadapter wird sofort erkannt und in Betrieb genommen.
Im Menü Network/Interfaces -> New Interface steht er als eth1 zur Auswahl:

Nachdem Submit gedrückt wurde kann man die IP Adresse und die Subnet Mask eingeben. Hier wird normalerweise kein Gateway eingetragen!
Da dieser Anschluss in Zukunft der interne LAN1 Anschluss ist, wird er der Firewall Zone "grün - lan" zugeordnet.

Wir haben jetzt einen Router mit zwei LAN Segmenten ohne NAT.

Routing vs Forwarding/NAT

Damit das LAN1 Segment aus dem LAN Segment erreichbar wird, muss der vorhandene Internetrouter eine zusätzliche Route für das Netzwerk LAN1 mit dem Gateway LAN bekommen.

Will man Router ohne Veränderung des existierendes Netzwerk betreiben braucht man NAT. NAT wird einfach durch die Firewall Zone WAN aktiviert, aber Vorsicht! Damit passieren zwei Dinge:

  • NAT wird aktiviert
  • Die Firewall Regeln sehen den Anschluss LAN dann sofort als Internetanschluss. Jeglicher eingehender Verkehr wird blockiert.

Wir greifen derzeit über den Anschluss (LAN) zu, dieser wird nach dieser Konfiguration nicht mehr aus dem Netzwerk LAN erreichbar sein! Also besser jetzt gleich zum Test und zur Konfiguration "das Notebook" an den LAN1 Anschluss verbinden und neu anmelden.
Interface LAN / Edit / Firewall Settings / WAN auswählen. So sieht das Ergebnis aus:

NAT wird innerhalb weniger Sekunden aktiviert und der Zugriff ins Netzwerk LAN und auch ins Internet sollte ohne Änderungen im existierenden Netzwerk funktionieren. Allerdings hat man jetzt meist doppeltes NAT, das verkraften nicht alle Anwendungen (z.B. VPN)

WLAN Interface

Auswahl des richtigen Adapters

Das ist gar nicht so einfach! Diese beiden Adapter habe ich nicht zum Laufen bekommen:
  • TP-LINK TL-WN725N v2 mit Realtek RTL8188EUS Chip
  • "Conrad" RE150U-PA-1T1R mit Realtek RTL8188SU Chip
Offenbar verhindern inkompatible Treiber den Betrieb als Routerinterface, im normalen Raspbian werde beide Adapter als Client unterstützt.
Diesen Adapter gab es preiswert und der hat auf Anhieb funktioniert. Er verleiht dem Ganzen durch seine beiden Antennen auch einen Router-mäßigen Eindruck:
  • CSL USB 2.0 WLAN Adapter 300Mbit (2,4/5GHz) mit Ralink RT5572 Chip
Nicht zu viel erwarten: der Adapter hat aber nur ein Radiointerface und kann 2,4 oder 5 GHz und nicht beides gleichzeitig!
Den Adapter stecken und lsusb gibt uns die entsprechende Information aus:
Bus 001 Device 004: ID 148f:5572 Ralink Technology, Corp. RT5572 Wireless Adapter
Der Chipsatz braucht das Softwarepaket kmod-rt2800-usb nach der Installation ist aber zunächst nicht viel passiert. Im Systemlog sollte aber eine Meldung in der Art auftauchen
kern.info kernel: [  624.833819] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 5592, rev 0222 detected
Ich habe Wireless im Menü zum Leben erweckt, in dem ich mutig auf der Seite System /Startup den network "Restart" Knopf gedrückt habe. Nach kurzem selbsttätigem Refresh der Oberfläche war der Punkt Network / Wireless sichtbar.
Bei einem neuerlichen Versuch mit OpenWrt 22.03 reicht der restart von network nicht, man muss das System neu starten.
Jetzt kann man das Wireless Netzwerk wie gewohnt einrichten.
Allerdings ist das Bild trügerisch. Es funktioniert noch nicht richtig!
OpenWrt braucht offenbar dafür noch etwas Software. Ich habe nur dieses Paket installiert, die anderen aus der dem Link waren nicht notwendig, obwohl die im Image von meinem WRT1900ACS von Hause aus drin waren. Ich werde das noch untersuchen, siehe Zusammenfassung.
  • block-mount
Danach kann man sich zumindest im 2,4 GHz Modus verbinden, wenn man einfach eine default Konfiguration wählt und bei Device Configuration/Advanced Settings Country Code DE auswählt.

Für eine funktionierende 5 GHz Konfiguration darf Channel nicht auf auto stehen - Bug oder Feature?

Zusammenfassung meiner minimalen Konfiguration

  • Beim Download das ext4 Image nehmen, mit dem squashfs Image bin ich nicht klar gekommen.
  • primäres LAN Interface: switch Protocol to DHCP Client
  • Zeitzone: Europe/Berlin
  • Software installieren: Update List
    • usbutils (optional)
    • kmod-usb-net-asix
    • kmod-rt2800-usb
    • block-mount - offenbar mit Version 18.06 obsolet?
Zumindest mit der neuen Version 18.06 funktioniert damit alles erst einmal. Der 5GHz Modus funktioniert nur mit fester Kanalwahl!

Doku OpenWrt Wireless overview
Doku OpenWrt WiFi configuration

Samstag, 16. Juni 2018

Mal schnell die IP Adresse umstellen

Man hat ein Gerät (z.B. Router) im Netz mit statischer IP der mal schnell umkonfiguriert werden muss? Wo war jetzt im aktuellen Windows nach dem letzten Update die Adapterkonfiguration hin verschwunden?

Geht auch ganz einfach mit Powershell:
Windows + x Taste drücken und Windows Powershell (Administrator) auswählen.

Hat man nur ein LAN Netzwerkinterface per DHCP am Netzwerk verbunden, erledigt dieses kleine Script die temporäre Umschaltung auf die Adresse 192.168.1.5 (um z.B. einen OpenWrt Router nach dem Start zu konfigurieren) 
$interface = Get-NetIPInterface -AddressFamily IPv4|where {$_.InterfaceAlias -match 'Ethernet' -and $_.Dhcp -eq 'enabled' -and $_.ConnectionState -eq 'Connected'}
$interface | New-NetIPAddress 192.168.1.5 -PrefixLength 24
pause
Set-NetIPInterface -InterfaceIndex $interface.ifIndex -Dhcp enabled
Restart-NetAdapter -name $interface.InterfaceAlias

Dienstag, 24. April 2018

Smartphone aus China ...

Naja irgendwie kommt ja scheinbar unsere gesamte Technik irgendwie daher. Ich habe seit einiger Zeit ein mi A1 und ein mi 6 - und ich komme auch immer mal in die Situation für jemanden das neue Smartphone in Betrieb zu nehmen. Da sind mir in letzer Zeit ein paar Besonderheiten aufgefallen und ich habe Verschiedenes versucht zu recherchieren.
Ich muss es einfach notieren. In einem halben Jahr hat man ja wieder viel vergessen oder es ist mit der neuen Version wieder ganz anders.
Diese Dinge sind nicht unbedingt vorhersehbar, logisch oder irgendwo genauso beschrieben. Ob es Besonderheiten der Smartphones von mi sind oder dies "allgemein Android"ist, kann ich nicht sagen.

Werksreset


Das ist mit irgendeiner Android Version etwas aufwendiger geworden. Ich beziehe mit aktuell auf Version 8.
Ein vom Nutzer eingerichtetes zusätzliches Sicherheitsmerkmal (Sperrcode: Pin, Muster oder Fingerabdruck) verschlüsselt wohl übrigens das gesamte Smartphone und man kann es ohne diesen Sperrcode nicht mehr starten!
Es handelt sich neben der Funktion der Ortung um eine Sicherung gegen Missbrauch nach Diebstahl oder Verlust.

Samsung S8 

Man kann im ausgeschalteten Zustand diese Tasten drücken:
drei Tasten gleichzeitig: Lauter + Bixby + Power
Nach Erscheinen vom Samsung Logo kann man loslassen und das Smartphone bootet in einen typischen "Bootloader", dort kann man Menügeführt alles löschen und das Smartphone damit zurücksetzen.
Startet man jetzt neu wird der oben erwähnte Sicherheitscode nicht mehr abgefragt!
Man kann jetzt das Smartphone neu einrichten - aber! Man kann es nur einrichten mit dem ehemals auf diesem Smartphone verwendeten Google Account! Ohne den wird jede Einrichtung verweigert: Meines Wissen keine Chance!
(Eventuell gibt es irgendwelche Reset Funktionen mit Code vom Hersteller, ADB, 72 Stunden warten usw.)

Es ist also wichtig, den Google Account vom Smartphone sicher zu haben, obwohl man vielleicht denkt man benutzt ihn nicht! Früher waren nur die Daten weg, heute wäre das Smartphone "weg"!

mi 6

Das mi 6 kann man nicht ohne weiteres "Hart" zurücksetzen. Die Tastenkombination Power + Volume- bootet lediglich den FASTBOOT Modus. Dort kann man meines Wissen nur mit ADB weitermachen.

Werksreset geht somit nur mit der Methode aus dem angemeldeten Smartphone heraus im Menü: Einstellungen/Sichern zurücksetzen/Auf Werkszustand zurücksetzen
(bzw. Mi Oberfläche und der derzeit gemischte Sprachversion,  Version MIUI Global 9.2.3.0):
Einstellungen/System&Device/Additional settings/Backup & reset/Auf Werkszustand zurücksetzen

Achtung: dieser Vorgang geht nur, wenn man vorher die Systemsprache auf english umgestellt hat! Wahrscheinlich hat die deutsche Oberfläche einen Bug!

Laut Beschreibung könnte man danach das Smartphone völlig neu einrichten, also auch an einen Fremden geben. Doch das stimmt nicht! Wenn man jetzt das Smartphone neu einrichten will wird erstmal wieder der alte Google Account verlangt!
Den alten Account muss man eingeben und dann kann man die Einrichtung (am Besten in english) ohne jegliches Konto durchführen. Danach kann man wieder einen Werksreset machen und jetzt kann man das Smartphone wirklich mit einem neuen Konto einrichten.

Es ist offenbar ein Bug des mi 6. Ich habe den gleichen Vorgang mit einem mi A1 getestet und es klappt wie erwartet.

Aber! Um sicher zu gehen, sollte man es unbedingt immer testen, bevor man das Smartphone an Fremde weiter gibt! Ich hatte in früheren Geräten auch schon den Fall, dass Bilder nicht gelöscht wurden!

GPS Daten

Beim mi 6 und dem mi A1 ist mir noch aufgefallen: Wenn man es ohne SIM Karte startet und einrichtet, ist GPS offenbar völlig desorientiert.  Man befindet sich in Marlborough district bzw. in Blenheim in Neuseeland. Das bleibt hartnäckig so, auch mit Internet (Wlan) Verbindung, auch tagelanges warten ändert dies nicht.
Bis man einmal die SIM Karte eingesteckt hat, dann ist er bereit ordentlich zu lokalisieren. Allerdings wird dann später mal wieder ohne SIM Karte gestartet ist er wieder erstmal in Neuseeland.


Sonntag, 25. Februar 2018

Windows Server Freigabe auf dem Raspberry verbinden

Ich will hier kurz zeigen wie der Zugriff auf eine Windows (Samba) Freigabe unter Raspbian eingerichtet wird. Im Raspbian Image (Lite vom November 2018) sind alle Voraussetzungen vorhanden, man muss nichts weiter installieren. In anderen Systemen kann es sein, dass man das debian Paket cifs-utils nachinstallieren muss.  Openmediavault hat z.B. bei aktiviertem Samba nicht automatisch cifs-utils installiert.
Für den praktischen Gebrauch muss man lediglich 3 Dinge konfigurieren, für einen schnellen Test  kann man es mit einem Zweizeiler machen (siehe weiter unten):

Pfad

Unter Linux braucht man einen Ort wo man ein Laufwerk "hin" mounten kann, dabei wird
\\Servername\Sharename auf den lokalen Pfad /DirName/DirName gemappt.
Man erzeugt einen Pfad, am Besten mit einer "Wurzel", einem Verzeichnis unter dem alle Netzlaufwerke eingehängt werden:
mp='/mnt/Sicherung'
sudo mkdir -p ${mp}
Die Option -p erzeugt alle notwendigen Ordner falls sie noch nicht existieren.

Benutzerkonto

Da ein Windows Server nicht ohne weiteres einen Zugriff ohne Login ermöglicht und wir username und password nicht immer eintippen wollen, werden die Informationen entsprechend abgelegt.
Dabei gibt es drei Möglichkeiten. Ja nach Vorliebe verwendet man einen Editor (nano) oder direkte Shellbefehle
1. persönliche Datei (notwendiger Inhalt siehe nächster Codeblock):
fcred='.smbcredentials'
nano $fcred
chmod 600 $fcred
Die Datei ist damit nur vom Eigentümer lesbar!

2. allgemeine Datei:
Wenn keine Domain verwendet wird, kann der Eintrag domain entfallen oder freibleiben.
fcred='.smbcredentials'
export datei="/usr/${fcred}" 
sudo bash -c "cat >${datei}" <<'EOF'
username=UserName
password=Userpassword
domain=
EOF
Man braucht pro Konto eine credentials Datei. Diese Datei muss von allen Usern lesbar sein, die mounten wollen. Die gerade angelegte Datei ist aber auch von "Jedem" lesbar, will man das eingrenzen, kann man das so machen:
sudo -s <<EOI
  addgroup cifs
  usermod -aG cifs fhem
  usermod -aG cifs pi
  chown root:cifs ${datei}
  chmod 640 ${datei}
EOI
Hinweis: Die Änderung der Gruppenmitgliedschaft wirkt erst nach Neuanmeldung!

3. anstatt extra Datei (credentials=Datei) schreibt man die Kontodaten direkt in die fstab Zeile, dort ohne Zeilentrennung!
username=ano,password=nym

fstab

Nun fehlt noch der mount Eintrag in der fstab. In meinem Beispiel wird nicht automatisch gemountet, alle User dürfen mounten und das Laufwerk ist beschreibbar.
sudo bash -c "echo //ServerName/daten ${mp} cifs noauto,users,credentials=/usr/.smbcredentials 0 0 >> /etc/fstab"

Verwendung

Jetzt können wir das Laufwerk einbinden, den erfolgreichen mount anzeigen und den Inhalt anzeigen. Das funktioniert ohne sudo, der Benutzer braucht Leserechte auf die credentials Datei.
mount ${mp}
df
ls -l ${mp}
umount ${mp}

Hinweis

Das Windows Laufwerk wird auf diese Art nicht automatisch beim Start angebunden. Das Netzwerk ist zu diesem Zeitpunkt noch nicht verfügbar und der automount über die fstab würde nicht funktionieren. Ist für mich kein Nachteil, weil es jederzeit in einem Script per mount Befehl angebunden werden kann.

Nachtrag

Man kann auch jederzeit  mit einem simplen "Zweizeiler" ein Windows Laufwerk als sudo mounten, password= kann man weglassen, dann wird es abgefragt.

sudo mkdir -p /mnt/daten
sudo mount -t cifs -o username=UserName,password=Passwort //ServerName/Freigabe /mnt/daten
# Bei smb1 Servern und ab debian stretch
sudo mount -t cifs -o username='UserName',password='Passwort',vers=1.0 //ServerName/Freigabe /mnt/daten

Bei Problemen kann man sich die verwendeten Dateisysteme bzw. die Unterstützung des Kernels  anzeigen lassen.
cat /proc/filesystems
ls /lib/modules/$(uname -r)/kernel/fs

Zum nachlesen: Ubuntu Wiki

SMB Protokoll

smb Version 1 wird mittlerweile als extrem unsicher eingestuft. Deswegen wird es aus modernen Systemen "entfernt".
Allerdings ist es in vielen Geräten nach wie Standard und eine Unterstützung von smb 2 oder 3 nicht implementiert (Fritzbox NAS, Sonos ...)
Windows hat ab Version 1709 das Protokoll entfernt, man muss es bei Bedarf mit "Windows Apps und Features" nachinstallieren (Neustart erforderlich)
debian stretch hat es offenbar als default aus der Aushandlung herausgenommen, mann muss es mit der cifs Option "vers=1.0" beim mount Befehl explizit hinzufügen, wenn der Server nur smb1 unterstützt.

Donnerstag, 8. Februar 2018

In FHEM externe Programme aufrufen

Es gibt viele Möglichkeiten ein externes Programm aufzurufen. Ich habe Einiges ausprobiert und hier sind meine Erkenntnisse. Es kann sein, dass sich Dinge ändern oder ich etwas nicht richtig verstanden habe. Meine Ausführungen sind mit Sicherheit nicht vollständig!
Dieser Beitrag endet mit konkreten Beispielen, die kann man exakt so übernehmen. Dabei sind die Anführungszeichen in den Codefenstern richtig und wichtig!
Empfehlung: Komplizierte und lange Codezeilen immer in ein Script oder in eine Perl Sub schreiben! Mit Sonderzeichen, doppelten und einfachen Anführungszeichen kommt man schnell in sehr unübersichtliche, beinahe unlösbare Situationen. Immer die mögliche Blockade von FHEM im Hinterkopf haben!

Aufruf

Es gibt drei FHEM Kommandotypen, sie unterscheiden sich in der Verwendung der "Klammer"
  • FHEM Befehl - keine Klammer
  • "Shell Befehl" - doppelte Anführungszeichen (blockiert FHEM nicht)
  • {Perl Befehl} - geschweifte Klammer (kann FHEM blockieren)
Für externe Programmaufrufe eignen sich die beiden letzeren.
Perl kennt in sich wieder drei Funktionsaufrufe für externe (nicht Perl) Programme.
  • system() - liefert in FHEM immer "-1" zurück, Ausgaben landen im Logfile
  • qx() - liefert die Ausgabe zurück, bei Aufruf in der FHEM Oberfläche landet diese im Browserfenster
  • exec() - in FHEM nicht sinnvoll! Beendet FHEM und das aufgerufene Programm wird ausgeführt.

Kurze Fingerübung

Der Code ist für die FHEM Kommandozeile!
"echo test"
Liefert nichts im Browserfenster, schreibt test ins Logfile.
Innerhalb von Perlcode kann man das auch so verwenden:
{fhem("\"echo test\"")}
Perl system() liefert -1 im Browserfenster und schreibt test ins Logfile.
{system("echo test")}
Variante von system() mit anderer Schreibweise: {system("programm","Arg1","Arg2")} und man bekommt das gleiche Ergebnis.
{system("echo","test")}
Perl qx() liefert test im Browserfenster und schreibt nichts ins Logfile.
{qx(echo test)}
Tipp: Diese Version verwende ich gern, um in der FHEM Oberfläche mal schnell etwas im System abzufragen. Man muss dazu nicht immer ins Terminal wechseln.

Achtung: Die Pipeline (> |) der Standardausgabe funktioniert nur bei {system("echo system > test.txt")} und {qx(echo qx > test.txt)}, bei "echo kommando > test.txt" versagt sie aber!

Zwischenspiel

Wie bekomme ich Text in eine Datei? Am Besten mit der Perlfunktion FileWrite
{FileWrite("test.txt","Inhalt")}
Das Ergebnis anschauen:
{qx(cat test.txt)}

Beispiel mit Wertübergabe von FHEM

Dieses mehrzeilige Beispiel ist für die Raw Definition!
Mit dem Code Block erzeugt man:
  • ein Shellprogramm (echo $(($1*$2))) welches beide Übergabewerte multipliziert.
  • ein Dummy mit dem Reading Wert,
  • ein notify welches den Wert und state an das Shell Programm übergibt und die Rückgabe wieder den Wert schreibt.
{FileWrite("ext_Script.sh","echo \$((\$1*\$2))")}

define ext_dummy dummy
attr ext_dummy readingList Wert
attr ext_dummy room extern
attr ext_dummy setList 0 1 2 3 4 5 6 7 8 9
setreading ext_dummy Wert 1

define ext_notify notify ext_dummy:[0-9] {\
 my $a = ReadingsVal($NAME,"Wert","2");;\
 my $b = qx(bash ext_Script.sh $EVENT $a);;\
 fhem("set $NAME Wert $b")\
}
attr ext_notify room extern
Diese Beispiel ist sicher etwas konstruiert, es zeigt aber verschiedenen Ebenen (FHEM, Perl, Shell) und auch die Übergabe von Werten über Variablen. Dabei gibt es einiges zu beachten:
Sonderzeichen in Textketten werden innerhalb einfacher und doppelter Anführungszeichen je nach Ebene unterschiedlich behandelt! Bei doppelten Anführungszeichen gilt:
  • Text der mit $ oder @ beginnt wird als Perl Variable/Array aufgelöst/ersetzt. Man kann/muss die Auflösung mit dem vorangestellten \ verhindern/schützen: "\$a , name\@domain.de". 
  • Ist das Anführungszeichen selbst nur Text: \".
  • Den \ muss man selbst schützen: \\.
  • Mit \ werden auch Steuerzeichen eingeleitet. z.B. \n ist ein Zeilenumbruch.
Immer dran denken: Den Befehlstrenner ; müssen wir in der FHEM Eingabezeile auch verdoppeln/schützen!

Beispiele zur Verwendung von Variablen

Zwei Perlzeilen und zwei Ebenen. Die Ausgabe ist gleich, die Variablen unterschiedlich.
  1. $a ist eine Perl Variable und der Inhalt wird von Perl zur Shell übergeben.
  2. $a ist eine Shell Variable und wird erst in der Shell erzeugt. Es wird nichts übergeben.
{my $a = "test";;qx "echo $a"}
{qx 'a=test;;echo $a'}
Der Syntax von qx ist sehr variabel, alle Zeilen bewirken das Gleiche: den letzten Fehlercode der Shell ausgeben
{qx "echo \$?"}
{qx 'echo $?'}
{qx /echo \$?/}
{qx (echo \$?)}
{`echo \$?`}
Mit einer Ausnahme könnte auch eine Perl Variablen übergeben werden (anstatt \$? $a).
Achtung: Die Verwendung von qx("") führt zu einer Fehlermeldung, da ist offenbar ein String Terminator zu viel.

Damit es nicht zu leicht wird, kann man die String Terminatoren natürlich auch schachteln. Für die Auflösung von Perl Variablen ist dabei die äußere Klammer bestimmend!
Das erste Beispiel gibt Hallo Welt aus, das zweite nur Hallo. Die Variable $a wird im zweiten Fall nicht aufgelöst, sondern als Shell Variable interpretiert.
{my $a = "Welt";;qx "echo 'Hallo $a'"}
{my $a = "Welt";;qx 'a=FHEM;;echo "Hallo $a"'}
Ausnahmen? Verwirrung?
Im folgenden Beispiel muss der Name der Variable im Shellscript auch geschützt werden.
Im Zweifelsfall hilft nur probieren!
{system('echo "wget --quiet - \"http://192.168.178.65/esp8266?max=Aussentemperatur+\$1+C\"" > ext_Script2.sh')}

Empfehlung: Befehle kapseln

Die Verwendung von Trennzeichen im String und die bisher genannten Interpretationen von Variablen Namen in den Umgebungen führt mich zu den unbedingten Empfehlung Befehle zu kapseln! Entweder in Stringvariablen in Perl oder in Scriptdateien für andere Sprachen. Es spart jede Menge Zeit und Nerven!

Verkettung / concatenation

Perl kennt noch die String Verkettung mit Punkten.
Im ersten Fall ist die Ausgabe identisch zur Version oben, im zweiten Fall wird der Inhalt der Variablen noch in Anführungszeichen ausgegeben:
{my $a = "test";;qx "echo ".$a}
{my $a = "test";;qx "echo ".'"'.$a.'"'}
Welche Methode man verwendet ist häufig Geschmacksache, manchmal aber auch vom Inhalt der Strings und dem gewünschten Ergebnis abhängig und damit das Mittel der Wahl.

Achtung blockierend

Die Ausführung von externen Programmen mit Perl Aufrufen wird FHEM für die Laufzeit dieses Programmes unterbrechen/anhalten. Das kann unvorhersehbare Folgen haben.
Der kurzer Perl Test erzeugt für 5 sec "Warten" und dann eine Ausschrift.
{sleep 5;; return "Das war eine Pause"}
{qx "echo Das war;;sleep 5;;echo eine Pause"}
Der zweite Test führt auf Shell Ebene ein sleep aus, beide echo Befehle werden aber erst am Ende über qx an den Browser zurück gegeben.
Für einen weiteren Test erzeugen wir uns wieder ein Shell Script.
{FileWrite("ext_Pause.sh","sleep \$1\necho \$1 sec Pause")}
Dies erwartet eine Zahl und macht dann eine entsprechende Pause. Mit einem qx() Aufruf können wir das Script testen.
{qx "echo Das war;;bash ext_Pause.sh 4"}
Nach meinen Informationen, lässt sich das Verhalten mit qx() nicht ändern. Die Befehle werden immer seriell ausgeführt, Perl wartet auf die Rückgabe!
Der system() Aufruf hat andere Möglichkeiten. Bei ihm kann man mit dem & Zeichen am Ende (für die Shell typisch) die Ausführung im Hintergrund starten. Die Ausgabe im Script landet damit nach der Pause im Logfile von FHEM.
{system ("bash ext_Pause.sh 5 &")}

Aufräumen

Um die hier beim Testen erzeugten Geräte und Dateien wieder zu entfernen, kann man die beiden Zeilen einzeln in der Kommandozeile oder zusammen in der Raw Definition ausführen.
delete ext_.*
{system ("rm ext_*.sh >/dev/null")}

Ganz zum Schluss

Mal noch als "Merker" der Tipp aus dem Forum. Den baue ich bei Gelegenheit mal noch aus.
Code Block