Freitag, 6. Mai 2016

Automatisches Mounten von verschlüsselten (LUKS) Devices mit Hilfe eines Active-Directory / LDAP-Server

Warum: 
Festplatten zu verschlüsseln um im Falle eines Diebstahles die Daten vor dem Zugriff zu schützen ist sinnvoll. Nur muss man dann eine Passwort eintippen oder ein Keyfile per USB-Stick bereitstellen. Ist der bootende Server mit LUKS-Verschlüsselung weit weg, kann zwar das Linux System hochfahren, aber die Dienste die auf die verschlüsselten Daten zu greifen müssen, können erst zu einem späteren Zeitpunkt gestartet werden. Zudem muss ja auch noch Alles manuell passieren.

Bedingungen / Voraussetzungen:
- Das Betriebssystem fährt ohne Verschlüsselung hoch.
- Die Systemplatten sind nicht verschlüsselt!
- LUKS verschlüsselte Partitionen
- Ein AD-Domänencontroller der stets verfügbar ist und sie haben Zugriffsrechte darauf.
- Zwei kleine Perl Scripte
- Systemd-Startscript

Ablauf-Prinzip:
Das System fährt hoch. Nachdem es Netzwerk-Zugriff hat, holt es sich per Perl-Script über LDAP die Keyfile-Daten aus dem LDAP-Attribute "extensionData" im AD. Dieses Attribut gehört zu jedem Computerkonto im AD.
Die Daten sind BASE64 kodiert und werden dann dekodiert in eine Datei geschrieben. Diese wiederum wird dem LUKS Command cryptsetup übergeben.
Über ein Systemd Startscript wird dieser Vorgang in den Boot- und Service-Startvorgänge eingebunden. Somit werden alle Dienste erst nach erfolgreichem mounten der LUKS-Partition(en) gestartet.

Prinzipiell kann natürlich auch ein beliebiger LDAP Server verwendet werden.

Umsetzung:

AD-Controller:
1. Ein AD Computerkonto erstellen
2. Ein AD User erstellen der NUR Leserecht auf das oder die Computerkonten hat

Linux-System:
3. Als root folgendes ausführen

# Installieren der Perl LDAP Pakete
zypper in perl-ldap-ssl perl-ldap perl-Authen-SASL perl-Digest-HMAC

# Generieren eines Zufalls-Schlüssels in der Datei keyfile
dd if=/dev/urandom of=/root/keyfile bs=1024 count=4

# Einfügen des Keyfiles Inhaltes in die LUKS Verschlüsselung
cryptsetup luksAddKey /dev/LUKS-Devie /root/keyfile

4. Anpassen des Perl Scriptes ldap-key-write.pl
Ersetzen aller FIRMA und COM  Platzhalter in den LDAP-Pfaden durch die Ihrer Firma! (2-3 Mal)

5.Das erstellte und als LUKS-Keyfile zum entschlüsseln verwendete "keyfile" wird dann mit Hilfe des Perl Scriptes "ldap-key-write.pl" ins ADS Computerkonto geladen.

6. ldap-key-read.pl konfigurieren und testen

7. Erstellen einer crypttab.orig files (per Tab getrennt) im Format
cr_dev      /dev/luks_device       none     noauto

8.  Kopieren des Systemd-Startup-Scriptes nach /etc/systemd/system/multi-user.target.wants/cryptmount.service

9. Kopieren des SystemV-Startup-Scriptes nach /etc/init.d/cryptmount

10. systemctl --system daemon-reload

11. Testen / Rebooten / Testen

 ! Have al lot of Fun :) !

 Files
--------  /etc/systemd/system/multi-user.target.wants/cryptmount.service ------------

[Unit]
Description=Mounted Crypt Volumes with Info from ADS / LDAP
Before=postgresql.service apache2.service nfsserver.service 
After=syslog.target network.target

[Service]
ExecStart=/etc/init.d/cryptmount start
Type=forking

[Install]
WantedBy=multi-user.target 

--------  /etc/systemd/system/multi-user.target.wants/cryptmount.service ------------

 --------  /etc/crypttab.orig. ------------
cr_sdb1         /dev/sdb1            none       noauto
 --------  /etc/crypttab.orig. ------------

 --------  /etc/init.d/cryptmount. ------------
#!/bin/sh

### BEGIN INIT INFO
# Provides:          cryptmount
# Required-Start:    $network
# Required-Stop:     $network
# Default-Start:     3 5
# Default-Stop:      0 1 2 6
# Short-Description: cryptmount provides mounting crypt partition with get the key from ADS
# Description:       Start cryptmount to allow mounting encrypted partitions
#       The key for unlock the partitions comming from ADS
### END INIT INFO 

# Check for existence of needed config file and read it
cryptmount_CONFIG=/etc/sysconfig/cryptmount

# openSuse Specials!!! 
 . /etc/rc.status

# Reset status of this service
rc_reset

case "$1" in
    start)
        echo -n "Starting cryptmount "

echo
ping -c 4 dc.firma.com
echo "##################"
ping -c 4 dc.firma.com
echo "##################"
/root/ldap-key-read.pl "CRYPT.keyfile"

while read CDEV QDEV KEY PARAM; 
do 
echo "START: $CDEV - $QDEV - $KEY - $PARAM"; 

        cryptsetup -d "/root/CRYPT.keyfile" luksOpen "$QDEV" "$CDEV"
        rm "/root/CRYPT.keyfile"
        mount /dev/mapper/$CDEV

done < /etc/crypttab.orig       

        # Remember status and be verbose
        rc_status -v
        ;;
    stop)
        echo -n "Shutting down cryptmount "
        ## Stop daemon with killproc(8) and if this fails
        ## killproc sets the return value according to LSB.
echo

while read CDEV QDEV KEY PARAM; 
do
        echo "TEST: $CDEV - $QDEV - $KEY - $PARAM";

        fgrep "$CDEV" /etc/fstab |  while read AA MOUNTPOINT REST;
        do
                TREFFER=`lsof | grep "$MOUNTPOINT" | wc -l`
                if [ "$TREFFER" -gt 0 ]; then
                        echo "WAITING FOR 5 sec";
                        sleep 5;
                fi 
        done;

done < /etc/crypttab.orig
while read CDEV QDEV KEY PARAM; 
do
echo "STOP: $CDEV - $QDEV - $KEY - $PARAM";
        
        umount /dev/mapper/$CDEV || (echo "UNMOUNT ERROR"; mount; lsof | grep /srv; )
        cryptsetup luksClose $CDEV 
done < /etc/crypttab.orig

        # Remember status and be verbose
        rc_status -v
        ;;
    restart)
        ## Stop the service and regardless of whether it was
        ## running or not, start it again.
        $0 stop
        $0 start

        # Remember status and be quiet
        rc_status
        ;;
    status)
        echo -n "Checking for service cryptmount "

echo
while read CDEV QDEV KEY PARAM; 
do
echo "STATUS: $CDEV - $QDEV - $KEY - $PARAM";
        cryptsetup status  $CDEV
        echo -n "MOUNTPOINT:"; mount | grep $CDEV
done < /etc/crypttab.orig

--------  /etc/init.d/cryptmount. ------------ 
 --------> ldap-key-read.pl. ----------->

#! /usr/bin/perl

use strict;   

use Net::LDAP;
use Authen::SASL qw(Perl);
use MIME::Base64;

my $SERVERNAME = "Your Servername";
my $user="cn=ldap,dc=FIRMA,dc=COM";
my $passwd='secret password';
my $DEVICE = $ARGV[0];

my $ldap = Net::LDAP->new("dc.firma.com");
$ldap->bind($user, password=>$passwd);
# "(objectClass=computer)"
my $mesg = $ldap->search(filter=>"&(name=$SERVERNAME)(objectClass=computer)", base=>"dc=firma,dc=com");
my @entries = $mesg->entries;
my $entry = $mesg->entry(0);
print "READ FROM DN: " . $entry->dn() . "\n"; 
my $content_base64 =  $entry->get_value('extensionData');

my $content_binary = MIME::Base64::decode($content_base64);

open( KEY, '>/root/'.$DEVICE ) or die ("Cannot open KEY file!\n");
binmode( KEY );

print KEY   $content_binary ;

close( KEY );

 <--------  ldap-key-read.pl.< ------------
 --------  ldap-key-write.pl. ------------>
 #! /usr/bin/perl 

use strict;   

use Net::LDAP;
use Authen::SASL qw(Perl);
use MIME::Base64;

my $content_binary;
my $content_base64;

my $DC = "
dc.firma.com";my $SERVERNAME = "Your Servername";
my $user="cn=$ARGV[0],dc=firma,dc=com";
print "PASSWORT eingeben:";
my $passwd;
$passwd = <STDIN>;
chomp( $passwd );

#print "USER: $user -- PW: $passwd\n";

my $ldap = Net::LDAP->new(
$DC);
$ldap->bind($user, password=>$passwd);
# "(objectClass=computer)"
my $mesg = $ldap->search(filter=>"&(name=$
SERVERNAME)(objectClass=computer)", base=>"dc=firma,dc=com");
my @entries = $mesg->entries;

my $dn = 'CN=$
SERVERNAME,CN=Computers,DC=firma,DC=com';
my $entry = $mesg->entry(0);


open( KEY, "<$ARGV[1]" ) or die ("Cannot open KEY file $ARGV[1] !\n");
binmode( KEY );

while(<KEY>)
{
#print KEY   $content_binary ;
$content_binary .= $_;
}
close( KEY );

my $content_base64 = MIME::Base64::encode($content_binary);

print "BASE: $content_base64\n";;

$mesg = $ldap->modify($dn, replace => { "extensionData" => $content_base64 } );
$entry->update($ldap);
print "Message is ". $mesg->code ." (". $mesg->error .").\n"; 

 <--------  ldap-key-write.pl. ENDE <------------


Donnerstag, 2. Mai 2013

Quasi-Deduplizierung mit BTRFS und Rsync für Backups von ESX oder PCs

Warum:
BTRFS unerstützt momentan keine Deduplizierung. Dieses Feature wäre aber für Backup und File-Dienste sehr wichtig, auch wen der Plattenplatz günstig ist. So hat man, wenn man ihn braucht, stets zu wenig zur Hand.

Prinzip-Ablauf:
Mittels RSYNC werden nur die Blöcke geschrieben, die sich bei den zu sichernden Dateien geändert haben. Wenn man dann mit Hilfe der Snapshot-Funktion ein Snapshot erstellt, werden nur die Änderungen zum Ausgangs-Ordner festgehalten. Soll bedeuten, das man ein Full-Backup vom Filesystem-Layout hat, aber nur die Datenmenge einer Differenzsicherung verbraucht.

Anwendung:
- lokale Sicherung von PCs und Laptop
Bsp.: Persönlich verwende ich eine USB-Festplatte (inkl. Verschlüsselung) auf diese werden als Vollsicherung meine Laptop Daten gesichert.

- Für die Sicherung von ESX-Images
Kann man dieses Verfahren ebenfalls nutzen, allerdings wird viel CPU Leistung benötigt. Leider kann man RSYNC nicht überreden seine Hashwerte über Blockgrössen von mehr als 128k zu berechnen. Ebenso muss man die ESX-Images zweimal kopieren. Einmal vom ESX auf die Storag-Einheit und von dort per RSYNC auf die eigentliche Sicherungsablage. ZFS wäre hier wohl die bessere WAhl, aber nur wenn man ein Storage-System mit genügend RAM für die Online-Deduplizierung hat.


# RSYNC Sicherung
rsync --stats --progress -av --partial --inplace --no-whole-file  SOURCE_PATH  DEST_PATH

# readonly Snapshot ziehen
btrfs subvolume snapshot -r DEST_PATH   DEST_PATH-DATUM

# Snapshots löschen
btrfs subvolume delete   DEST_PATH-DATUM

Zusätzlich können exclude-Listen für die PC/Laptop Sicherung mit eingebunden werden.


Montag, 29. April 2013

P2V - Clone eines Linux Systems (OpenSuse) mit Boardmitteln

Ausgangspunkt war ein altes Linux System mit OpenSuse 11.3 das ich virtualisieren wollte. Die Anwendungen waren eine Oracle DB und ein Wiki dessen Lebenszeit dem Ende zuging. Zudem war die Hardware mehr als genug für diese Zwecke. Also war mein erster Gedanke den ESX-Converter von VMware zu nehmen.
Der ESX Converter existiert nur noch in einer alten Version mit der man auf ESX Systemen größer als Version 4.X nichts mehr mit anfangen kann. Die Windows Version wollte ich nicht auf meine bestehenden Server installieren. Also mußte eine andere Variante her.

Zum Clonen mit Boardmitteln benötigen wir:
- Ein ESX Server
- eine VM-Config für das zukünftige Linux-System inkl. Festplatten und Netzwerk wie im Original System
- SSH Zugang zum alten Linux System

Das Original System:
CPU:  4xXEON ohn HT
RAM: 8GB
HDD: sda und sdb mit jeweils mehren hundert Gigabyte Größe
App: Apache, Perl-Wiki, PostgreSQL-DBs, Oracle-DB mit APEX
OS: OpenSuse 11.3

Das Clone System:
- läuft auf ESX5
- HDD, RAM und NICs identisch in Anzahl bzw. Größe konfiguriert

Prinzip-Ablauf:
Auf dem Clone System mit einer Rescue System booten und die Festplatten-Inhalte per dd Command und der Secure Shell in die Raw Device der virtuellen Maschine schreiben.e


################################################################
# Auf Original-System:
################################################################


# Ausgabe der Partitions Tabellen in eine Datei

sfdisk -d /dev/sda > partition_sda.txt
sfdisk -d /dev/sdb > partition_sdb.txt

# Bei Bedarf anpassen
# Beispiel Ausgabe 
# partition table of /dev/sdb
unit: sectors

/dev/sdb1 : start=       63, size=398294721, Id=83
/dev/sdb2 : start=        0, size=        0, Id= 0
/dev/sdb3 : start=        0, size=        0, Id= 0
/dev/sdb4 : start=        0, size=        0, Id= 0



################################################################
# Clone-System:
################################################################

# Rescue Disk booten - OpenSuse 12.3 (Network ISO)

# Netzwerk Zugriff einrichten

# IP Adresse hinzufügen
ip addr add 192.168.0.40/24 dev eth0
# Std-Gateway setzen
ip route add default via 192.168.0.1 dev eth0
# Prüfung
ip addr
ip route


# SSH Daemon starten
rcsshd start
# Root Passwort zur Anmeldung setzen
passwd root


################################################################
# Auf Original-System:
################################################################

# Beschreibung der Partitionstabellen kopieren
scp ./partition_sd*.txt root@192.168.0.40:/root

################################################################
# Clone-System:
################################################################

# Einspielen der Partition-Table
sfdisk /dev/sda < partition_sda.txt
sfdisk /dev/sdb < partition_sdb.txt


################################################################
# Auf Original-System:
################################################################

# Dienste stoppen
/etc/init.d/oracle_stop_all
rcpostgresql stop
rcapache2 stop
rcsmb stop
rcnmb stop
rcwinbind stop
cnfsserver stop
rccups stop
rcrpcbind stop
rcpostfix stop

# Alle Cronjobs deaktivieren
crontab -e

# Daten Blockweise kopieren, bei Bedarf mit Gzip o.ä.
dd if=/dev/sda1  | ssh 192.168.0.40 dd of=/dev/sda1 # Swap-Part.
dd if=/dev/sda2  | ssh 192.168.0.40 dd of=/dev/sda2 # Root-Part.
dd if=/dev/sdb1  | ssh 192.168.0.40 dd of=/dev/sdb1 # Data-Part.

# Bsp mit gzip
# dd if=/dev/sda1 | gzip  --fast -c  | ssh 192.168.0.40 "gzip -d -c | dd of=/dev/sda1"

# Die Komprimierung mittels Gzip lohnt sich nicht
# Die Zeit für die Komprimierung ist sehr hoch und der Gewinn niedrig da die Daten sich schlecht    
# komprimieren lassen. Man könnte höchstens den leeren Festplattenplatz mittels einer risiegen Datei 
# mit 0 oder 1 beschreiben und dann löschen. Dann könnte Gzip diesen leeren Festplattenplatz gut 
# komprimieren. 

################################################################
# Clone-System:
################################################################

# Log des Filesystems zurücksetzen, da während des Kopiervorganges Änderungen am System  wahrscheinlich durchgeführt wurden

# XFS Log zurücksetzen
xfs_repair -L /dev/sda2
xfs_repair -L /dev/sdb1

# Ausgabe könnte so aussehen
xfs_repair -L /dev/sdb1
Phase 1 - find and verify superblock...
Phase 2 - using internal log
        - zero log...
        - scan filesystem freespace and inode maps...
block (1,10584775-10584775) multiply claimed by cnt space tree, state - 2
agi_freecount 214, counted 215 in ag 1
sb_ifree 1071, counted 1072
        - found root inode chunk
Phase 3 - for each AG...
        - scan and clear agi unlinked lists...
        - process known inodes and perform inode discovery...
        - agno = 0
        - agno = 1
corrupt block 0 in directory inode 268435745
        will junk block
no . entry for directory 268435745
no .. entry for directory 268435745
problem with directory contents in inode 268435745
cleared inode 268435745
data fork in ino 363511577 claims free block 22729164
imap claims a free inode 369521264 is in use, correcting imap and clearing inode
cleared inode 369521264
imap claims a free inode 369521266 is in use, correcting imap and clearing inode
cleared inode 369521266
imap claims a free inode 369521286 is in use, correcting imap and clearing inode
cleared inode 369521286
imap claims a free inode 369521290 is in use, correcting imap and clearing inode
cleared inode 369521290
        - agno = 2
        - agno = 3
        - process newly discovered inodes...
Phase 4 - check for duplicate blocks...
        - setting up duplicate extent list...
        - check for inodes claiming duplicate blocks...
        - agno = 0
        - agno = 1
        - agno = 2
        - agno = 3
entry "maildrop" at block 0 offset 312 in directory inode 805306538 references free inode 268435745
        clearing inode number in entry at offset 312...
Phase 5 - rebuild AG headers and trees...
        - reset superblock...
Phase 6 - check inode connectivity...
        - resetting contents of realtime bitmap and summary inodes
        - traversing filesystem ...
bad hash table for directory inode 805306538 (no data entry): rebuilding
rebuilding directory inode 805306538
        - traversal finished ...
        - moving disconnected inodes to lost+found ...

disconnected inode 369520539, moving to lost+found
disconnected inode 369520540, moving to lost+found
disconnected inode 369521250, moving to lost+found
disconnected inode 369521251, moving to lost+found
disconnected inode 369521291, moving to lost+found
Phase 7 - verify and correct link counts...
resetting inode 805306538 nlinks from 16 to 15
done

# Ich habe keine Daten verloren! Und ich habe das Verfahren mehrfach angewendet.
# Deshalb habe ich auch die DBs heruntergefahren! Selbst mit allen laufenden Programmen geht es gut

# Boot-Konfig anpassen

# Vorbereitung 
# Ich befinde mich noch auf der Rescue Konsole der Rettungs-DVD von OpenSuse!!!
# Diese Verzeichnisse werden benötigt um die folgenden Konfig-Programme wie Grub2 korrekt laufen zu lassen

mount /dev/sda2 /mnt/
mount /dev/sdb1 /mnt/var/
mount --bind /dev   /mnt/dev
mount --bind /proc  /mnt/proc

# Ändere Root 
chroot /mnt

# GRUB neu einspielen
# Bei Grub Fehler 21:
# Error 21: Selected disk does not exist
grub-install --recheck /dev/sda

# Ansonsten nur dieses hier
grub --batch < /etc/grub.conf

# Noch in der chroot Umgebung? Wichtig für die Pfadangabe

vi /boot/grub/menu.lst # Alte HDD Verweise durch neue ersetzen
# Hier /dev/disk/by-label durch /dev/sda2

# RAM-Disk neu erstellen
mkinitrd
Ausgabe:
Kernel image:   /boot/vmlinuz-2.6.34.10-0.6-default
Initrd image:   /boot/initrd-2.6.34.10-0.6-default
Root device:    /dev/sda2 (mounted on / as xfs)
Kernel Modules: scsi_mod aacraid thermal_sys thermal libata ata_piix ata_generic processor fan exportfs xfs scsi_transport_spi mptbase mptscsih mptspi sd_mod 
Features:       block resume.userspace resume.kernel
Bootsplash:     openSUSE (1024x768)
38025 blocks

Kernel image:   /boot/vmlinuz-2.6.34.10-0.6-desktop
Initrd image:   /boot/initrd-2.6.34.10-0.6-desktop
Root device:    /dev/sda2 (mounted on / as xfs)
Kernel Modules: scsi_mod aacraid thermal_sys thermal libata ata_piix ata_generic processor fan exportfs xfs scsi_transport_spi mptbase mptscsih mptspi sd_mod 
Features:       block resume.userspace resume.kernel
Bootsplash:     openSUSE (1024x768)
38129 blocks

# Mountpoints anpassen
vi /etc/fstab

# Änderung für die Home-Partition 
# Wurde von /home nach /var/home verschoben. Damit aber die Apps 
# nichts davon bemerken machen wir hier ein Rebind und tragen diesen 
# in die /etc/fstab ein

/var/home            /home               none                              0 0

# Da neue NICs auch neue MAC-IDs mitbringen, würden neue Einträge erstellt werden
# Dies wird hiermit verhindert!
vi /etc/udev/rules.d/70-persistent-net.rules

# Ausgabe
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:AA:BB:CC:11:22", ATTR{type}=="1", KERNEL=="wlan*",NAME="wlan0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*",TTR{address}=="00:AA:BB:CC:11:23", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

# IP Adressen anpassen, da Altsystem noch läuft
# Entweder neues System und neue IP
# oder altes System neue IP und neues System behält die alten bei.

# Auf dem Original System ==> vi /etc/sysconfig/network/ifcfg-eth0 und die IP ändern

# Reboot der Clone Systems
reboot

Das sollte es gewesen sein. Hiernach ist das alte System unter einer anderen IP erreichbar bzw. ausgeschaltet. Und das neue System (Clone) behält die alte IP und kann nach starten der gestoppten Dienste weitermachen wie bisher.
Die Dauer der Umstellung hängt das allein von den Datenmengen ab die kopiert werden müssen.
Ich mußte 230 GB Daten kopieren, bei 1GBit Netzwerk, sind das rund 1 Stunde und 20 min bei ca. 50 MB/sec.


Mittwoch, 14. November 2012

ipconfig Script für Linux


Ein IPCONFIG Script für Linux

Um alle Informationen die das gleichnamige Tool bereithält auch für mein Lieblings OS auszugeben muss man doch einiges zusammensuchen.
Als da wären:

  • IP Adresse / Subnetzmask
  • Default Gateway
  • DNS Server 
  • DNS Domaine
  • Rechnername (FQDN)
  • MAC-ID der Interfaces
Die Ausgabe sieht so aus


Netzwerk-Konfiguration
----------------------

Rechnername......... recner.domain.de
DNS-Domaine......... 

DNS-Server.......... 192.168.0.2

Default Gateway..... 192.168.0.1

Netzwerk-Interface.. eth0
    MAC-ID.......... 13:1E:AS:CD:FA:A9
    IP-Adresse...... 192.168.0.63
    SubnetMask...... 255.255.255.0

Netzwerk-Interface.. lo
    MAC-ID.......... 
    IP-Adresse...... 127.0.0.1
    SubnetMask...... 255.0.0.0

Netzwerk-Interface.. wlan0
    MAC-ID.......... 13:1E:AS:CD:FA:A9
    IP-Adresse...... 192.168.220.63
    SubnetMask...... 255.255.255.248


Das Script habe ich schon vor vielen Jahren geschrieben und wollte es endlich mal dokumentieren und der Öffentlichkeit zugänglich machen. Es müssen die Dateien: "/etc/resolv.conf" und die Ausgaben von "ip route" und "ifconfig -a" ausgewertet werden

Script-Code:

#! /bin/sh
clear
echo " "
echo "Netzwerk-Konfiguration"
echo "----------------------"
echo " "
echo " "
echo "Rechnername......... "`hostname`

test -f /etc/resolv.conf && DOMAIN=`cat /etc/resolv.conf | grep domain | grep -v '#'`
echo "DNS-Domaine......... "${DOMAIN#* }
echo " "

if test -f /etc/resolv.conf; then
    Text="DNS-Server.......... "
    cat /etc/resolv.conf | grep nameserver | grep -v '#' | while read name NAMESERVER ; do
        echo $Text$NAMESERVER
        Text=".................... "
    done
echo " "
fi

LinkName="Link"
LANG=""
export LANG=""

/sbin/ip route  | while read AAA BBB gateway DDD EEE ; do
        if test "$AAA" = "default" ; then                   
            echo "Default Gateway..... "${gateway}
            TREFFER="true";
        fi
            
done 
echo " "

#if [ "$TREFFER" != "true" ]; then
#       echo "Default Gateway....."
#fi

/sbin/ifconfig -a  | while read ifname Name flags MACname MAC ; do
        if test "$Name" = "$LinkName" ; then                
            read inet ipaddr broadcast mask
            if test "${inet}" != "inet" ; then
                ipaddr="";
                mask="";
                broadcast="";
            fi
            echo "Netzwerk-Interface.. "${ifname}
            echo "    MAC-ID.......... "$MAC
            echo "    IP-Adresse...... "${ipaddr#*:}
            if [ "${mask}" = "" ]; then
                mask=$broadcast         
            fi
            echo "    SubnetMask...... "${mask#*:}
            mask=""
            broadcast=""
            echo " "
        fi
            
done 

Natürlich sollte inzwischen der Befehl ifconfig durch "ip addr" ersetzt werden.