Die Bash-Shell bietet zahlreiche Möglichkeiten zur Interaktion mit Netzwerkressourcen. Durch die geschickte Kombination von Netzwerkbefehlen in Shell-Skripten können Administratoren und Entwickler effiziente Werkzeuge zur Überwachung, Diagnose und Automatisierung von Netzwerkaufgaben erstellen.
Die folgenden Kernbefehle bilden das Fundament für Netzwerkoperationen unter Linux:
ping: Prüft die Erreichbarkeit eines Hosts durch das Senden von ICMP-Echo-Anfragen.
# Grundlegende Verwendung
ping example.com
# Begrenzung auf eine bestimmte Anzahl von Anfragen
ping -c 4 192.168.1.1
# Intervall zwischen Ping-Anfragen festlegen (in Sekunden)
ping -i 2 example.comtraceroute/tracepath: Zeigt den Pfad an, den Pakete zu einem Zielhost nehmen, und misst die Übertragungsverzögerung.
# Standardverwendung
traceroute example.com
# Verwendung mit UDP-Paketen
traceroute -U example.com
# Alternative mit weniger Privilegien
tracepath example.comnetstat/ss: Zeigt Netzwerkverbindungen,
Routing-Tabellen und Schnittstellenstatistiken an. Der neuere
ss-Befehl ist schneller und bietet erweiterte
Funktionen.
# Alle offenen Ports anzeigen
netstat -tuln
# Verbindungen mit PID und Programmnamen
netstat -tulnp
# Mit ss (Socket Statistics)
ss -tulnip: Ein leistungsstarkes Werkzeug zur Konfiguration
und Anzeige von Netzwerkschnittstellen, Routen und mehr. Es ersetzt
ältere Befehle wie ifconfig und route.
# Netzwerkschnittstellen anzeigen
ip addr show
# Routing-Tabelle anzeigen
ip route show
# ARP-Tabelle anzeigen
ip neigh showdig/nslookup/host: Werkzeuge zur DNS-Abfrage und -Diagnose.
# Detaillierte DNS-Informationen abfragen
dig example.com
# Einfachere Alternative
nslookup example.com
# Kompakte Ausgabe
host example.com
# Reverse-DNS-Lookup
dig -x 8.8.8.8Ein einfaches Skript zur Überwachung der Erreichbarkeit mehrerer Hosts könnte wie folgt aussehen:
#!/bin/bash
# Datei mit Hostnamen oder IP-Adressen
HOSTS_FILE="/path/to/hosts.txt"
LOG_FILE="/var/log/host_monitor.log"
MAX_TIMEOUT=2 # Timeout in Sekunden
if [[ ! -f "$HOSTS_FILE" ]]; then
echo "Fehler: Hosts-Datei nicht gefunden: $HOSTS_FILE" >&2
exit 1
fi
date_str=$(date "+%Y-%m-%d %H:%M:%S")
echo "=== Netzwerk-Check gestartet: $date_str ===" >> "$LOG_FILE"
while read -r host; do
# Kommentare und leere Zeilen überspringen
[[ "$host" =~ ^# ]] || [[ -z "$host" ]] && continue
echo "Prüfe Host: $host" >> "$LOG_FILE"
# Ping mit einem Timeout und nur einem Paket
if ping -c 1 -W "$MAX_TIMEOUT" "$host" &>/dev/null; then
echo " Status: ERREICHBAR" >> "$LOG_FILE"
else
echo " Status: NICHT ERREICHBAR" >> "$LOG_FILE"
# Optional: Alarmierung per E-Mail oder andere Aktionen
fi
done < "$HOSTS_FILE"
echo "=== Netzwerk-Check beendet ===" >> "$LOG_FILE"Die Bash bietet eine spezielle Dateisystem-Notation, mit der direkt auf TCP- und UDP-Sockets zugegriffen werden kann. Diese Funktionalität ist extrem nützlich, wenn keine spezialisierten Netzwerktools verfügbar sind.
#!/bin/bash
# HTTP-Anfrage an einen Webserver senden
exec 3<>/dev/tcp/example.com/80
echo -e "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n" >&3
cat <&3
exec 3>&- # Socket schließenDieses Beispiel öffnet eine TCP-Verbindung zum Port 80 von example.com, sendet eine HTTP-Anfrage und gibt die Antwort aus.
Ein einfacher Port-Scanner kann mit der /dev/tcp-Notation implementiert werden:
#!/bin/bash
HOST="192.168.1.1"
START_PORT=1
END_PORT=1024
TIMEOUT=1
echo "Scanne Ports $START_PORT bis $END_PORT auf $HOST..."
for port in $(seq $START_PORT $END_PORT); do
(timeout $TIMEOUT bash -c "echo > /dev/tcp/$HOST/$port" 2>/dev/null &&
echo "Port $port ist offen") &
# Begrenze die Anzahl der gleichzeitigen Prozesse
if [[ $(jobs -r | wc -l) -ge 20 ]]; then
wait -n
fi
done
wait # Warte auf alle Hintergrundprozesse
echo "Scan abgeschlossen."Mit den Befehlen iftop oder nethogs können
Sie die Netzwerknutzung überwachen. Ein einfaches Skript zur
regelmäßigen Erfassung der Netzwerkstatistiken:
#!/bin/bash
INTERFACE="eth0"
LOG_FILE="/var/log/network_stats.log"
INTERVAL=300 # Sekunden
# Prüfe, ob das Interface existiert
if ! ip link show "$INTERFACE" &>/dev/null; then
echo "Fehler: Interface $INTERFACE nicht gefunden" >&2
exit 1
fi
while true; do
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
# Netzwerkstatistiken aus /proc/net/dev erfassen
stats=$(grep "$INTERFACE:" /proc/net/dev | awk '{print $2, $10}')
rx_bytes=$(echo "$stats" | awk '{print $1}')
tx_bytes=$(echo "$stats" | awk '{print $2}')
echo "$timestamp,$INTERFACE,$rx_bytes,$tx_bytes" >> "$LOG_FILE"
sleep "$INTERVAL"
doneDie Tools curl und wget bieten
fortgeschrittenere Funktionen für HTTP/HTTPS und andere Protokolle:
#!/bin/bash
# Grundlegende GET-Anfrage
curl -s https://api.example.com/status
# POST-Anfrage mit JSON-Daten
curl -X POST \
-H "Content-Type: application/json" \
-d '{"key": "value"}' \
https://api.example.com/update
# Datei herunterladen mit Fortschrittsanzeige
wget --progress=bar https://example.com/large-file.tar.gz
# Website-Zustand überwachen
check_website() {
local url="$1"
local expected_status="$2"
# HTTP-Statuscode abrufen
status=$(curl -s -o /dev/null -w "%{http_code}" "$url")
if [[ "$status" == "$expected_status" ]]; then
echo "OK: $url returned status $status"
return 0
else
echo "FEHLER: $url returned status $status (expected $expected_status)"
return 1
fi
}
# Verwendung
check_website "https://example.com" "200"Ein typisches Anwendungsszenario ist die Verarbeitung von Serverprotokollen zur Erkennung von Angriffen:
#!/bin/bash
LOG_FILE="/var/log/auth.log"
THRESHOLD=5 # Schwellenwert für fehlgeschlagene Anmeldeversuche
BAN_SCRIPT="/usr/local/bin/ban_ip.sh"
# Fehlgeschlagene SSH-Anmeldeversuche zählen
failed_attempts=$(grep "Failed password" "$LOG_FILE" | awk '{print $11}' | sort | uniq -c)
echo "$failed_attempts" | while read count ip; do
if [[ $count -ge $THRESHOLD ]]; then
echo "IP $ip hat $count fehlgeschlagene Anmeldeversuche"
# Optional: IP-Adresse blockieren
if [[ -x "$BAN_SCRIPT" ]]; then
"$BAN_SCRIPT" "$ip"
echo "IP $ip wurde blockiert"
fi
fi
doneBei der Implementierung von Netzwerkoperationen in Shell-Skripten sollten Sie folgende Best Practices berücksichtigen:
Diese grundlegenden Netzwerkbefehle und Techniken bilden das Fundament für die Entwicklung leistungsfähiger Netzwerk-Monitoring- und Automatisierungsskripte in Bash. Mit zunehmender Komplexität der Anforderungen empfiehlt es sich jedoch, spezialisierte Tools wie Python oder spezialisierte Netzwerk-Monitoring-Systeme in Betracht zu ziehen.
Die Tools curl und wget sind mächtige
Kommandozeilenprogramme, die für den Transfer von Daten über
verschiedene Netzwerkprotokolle entwickelt wurden. Beide eignen sich
hervorragend für die Integration in Shell-Skripte und ergänzen die
Netzwerkfähigkeiten der Bash erheblich. Während sie sich in einigen
Funktionalitäten überschneiden, haben sie unterschiedliche Stärken und
Einsatzgebiete.
curl (Client URL) ist ein vielseitiges Werkzeug zum
Übertragen von Daten mit URL-Syntax. Es unterstützt zahlreiche
Protokolle, darunter HTTP, HTTPS, FTP, FTPS, SCP, SFTP, LDAP und
mehr.
# Grundlegende Anfrage - Ausgabe auf stdout
curl https://example.com
# Stille Ausgabe (nur Inhalt, keine Fortschrittsanzeige)
curl -s https://example.com
# Ausgabe in eine Datei umleiten
curl -o output.html https://example.com
# Datei mit Originalname speichern
curl -O https://example.com/document.pdf# Header einer Anfrage anzeigen
curl -I https://example.com
# Benutzerdefinierte Header senden
curl -H "User-Agent: MeinScript/1.0" \
-H "Accept: application/json" \
https://api.example.com
# Nur Response-Header anzeigen
curl --head https://example.com# POST-Anfrage mit Formular-Daten
curl -X POST \
-d "username=benutzer&password=geheim" \
https://example.com/login
# POST mit JSON-Daten
curl -X POST \
-H "Content-Type: application/json" \
-d '{"username":"benutzer","password":"geheim"}' \
https://api.example.com/login
# PUT-Anfrage zum Aktualisieren von Ressourcen
curl -X PUT \
-H "Content-Type: application/json" \
-d '{"status":"active"}' \
https://api.example.com/users/123
# DELETE-Anfrage
curl -X DELETE https://api.example.com/users/123# Basic Authentication
curl -u username:password https://example.com/secured
# OAuth2 Bearer Token
curl -H "Authorization: Bearer mein_access_token" \
https://api.example.com/protected-resource# Cookies speichern
curl -c cookies.txt https://example.com/login
# Gespeicherte Cookies verwenden
curl -b cookies.txt https://example.com/dashboard
# Cookies in derselben Session verwenden
curl -b cookies.txt -c cookies.txt https://example.com/next-page# Maximale Übertragungszeit festlegen
curl --max-time 10 https://example.com
# HTTP-Weiterleitungen folgen
curl -L https://example.com/redirect
# Proxy verwenden
curl -x http://proxy.example.com:8080 https://target.com
# Zertifikatsprüfung überspringen (nur zu Testzwecken!)
curl -k https://self-signed.example.com
# Ausgabe mit detaillierten Informationen
curl -v https://example.com
# Nur bestimmte HTTP-Statuscode akzeptieren
curl --write-out "%{http_code}\n" --silent --output /dev/null https://example.comwget ist spezialisiert auf das nicht-interaktive
Herunterladen von Dateien. Es ist besonders nützlich für große Downloads
und gespiegelte Websites.
# Grundlegende Verwendung
wget https://example.com/file.zip
# Ausgabedatei umbenennen
wget -O neuername.zip https://example.com/file.zip
# Im Hintergrund ausführen
wget -b https://example.com/large-file.iso# Website spiegeln (mit Einschränkungen)
wget -m -p -k https://example.com
# Rekursiv mit Tiefenbegrenzung
wget -r -l 2 https://example.com# Bandbreitenbegrenzung (auf 100KB/s)
wget --limit-rate=100k https://example.com/large-file.iso
# Fortsetzung unterbrochener Downloads
wget -c https://example.com/large-file.iso
# Retry bei Fehler
wget -t 5 https://unreliable-server.com/file.zip# Basic Auth
wget --user=username --password=password https://example.com/secure
# Verwenden von .netrc für Anmeldedaten
wget --use-askpass https://example.com/secure#!/bin/bash
API_KEY="your_api_key"
CITY="Berlin"
OUTPUT_FILE="/tmp/weather_report.json"
# OpenWeatherMap API abfragen
curl -s "https://api.openweathermap.org/data/2.5/weather?q=${CITY}&appid=${API_KEY}&units=metric" > "$OUTPUT_FILE"
# Daten extrahieren mit jq (wenn verfügbar)
if command -v jq &>/dev/null; then
temperature=$(jq '.main.temp' "$OUTPUT_FILE")
description=$(jq -r '.weather[0].description' "$OUTPUT_FILE")
echo "Wetter in $CITY: $description, $temperature°C"
else
# Alternativ mit grep und awk
temperature=$(grep -o '"temp":[^,]*' "$OUTPUT_FILE" | awk -F: '{print $2}')
echo "Temperatur in $CITY: $temperature°C"
fi#!/bin/bash
# Zu überwachende Websites
SITES=("https://example.com" "https://example.org" "https://example.net")
LOG_FILE="/var/log/website_monitor.log"
ALERT_SCRIPT="/path/to/alert.sh"
check_website() {
local url="$1"
local start_time=$(date +%s.%N)
# HTTP-Statuscode und Antwortzeit messen
local response=$(curl -s -w "%{http_code},%{time_total}" -o /dev/null "$url")
local status_code=$(echo "$response" | cut -d, -f1)
local response_time=$(echo "$response" | cut -d, -f2)
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
if [ "$status_code" -eq 200 ]; then
echo "$timestamp - $url - OK (Status: $status_code, Zeit: ${response_time}s)" >> "$LOG_FILE"
return 0
else
echo "$timestamp - $url - FEHLER (Status: $status_code, Zeit: ${response_time}s)" >> "$LOG_FILE"
# Alarmierung, wenn Status nicht 200 ist
if [ -x "$ALERT_SCRIPT" ]; then
"$ALERT_SCRIPT" "$url" "$status_code" "$response_time"
fi
return 1
fi
}
# Jede Website prüfen
for site in "${SITES[@]}"; do
check_website "$site"
done#!/bin/bash
DOWNLOAD_URL="https://example.com/daily-report.csv"
DOWNLOAD_DIR="/var/data/reports"
ARCHIVE_DIR="/var/data/archive"
LOG_FILE="/var/log/download.log"
# Sicherstellen, dass die Verzeichnisse existieren
mkdir -p "$DOWNLOAD_DIR" "$ARCHIVE_DIR"
# Aktuelles Datum für Dateinamen
DATE=$(date +%Y-%m-%d)
FILENAME="report-$DATE.csv"
log() {
echo "$(date "+%Y-%m-%d %H:%M:%S") - $1" >> "$LOG_FILE"
}
# Download mit wget
log "Starte Download von $DOWNLOAD_URL"
if wget -q --tries=3 --timeout=15 -O "$DOWNLOAD_DIR/$FILENAME" "$DOWNLOAD_URL"; then
log "Download erfolgreich: $FILENAME"
# Datei verarbeiten
RECORD_COUNT=$(wc -l < "$DOWNLOAD_DIR/$FILENAME")
log "Anzahl der Datensätze: $RECORD_COUNT"
# Archivierung
gzip -c "$DOWNLOAD_DIR/$FILENAME" > "$ARCHIVE_DIR/$FILENAME.gz"
log "Datei archiviert: $ARCHIVE_DIR/$FILENAME.gz"
# Weitere Verarbeitung hier...
else
log "Download fehlgeschlagen mit Fehlercode $?"
exit 1
fi#!/bin/bash
API_BASE="https://api.example.com/v1"
TOKEN="your_access_token"
CONFIG_FILE=".api_config"
# Konfigurationsdatei laden, falls vorhanden
if [[ -f "$CONFIG_FILE" ]]; then
source "$CONFIG_FILE"
fi
# API-Anfrage-Funktion mit curl
api_request() {
local method="$1"
local endpoint="$2"
local data="$3"
# Header für alle Anfragen
local headers=(
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-H "Accept: application/json"
)
# Anfrage ausführen
if [[ -n "$data" ]]; then
curl -s -X "$method" "${headers[@]}" -d "$data" "${API_BASE}${endpoint}"
else
curl -s -X "$method" "${headers[@]}" "${API_BASE}${endpoint}"
fi
}
# Verschiedene API-Funktionen
get_resource() {
local resource_id="$1"
api_request "GET" "/resources/$resource_id"
}
create_resource() {
local resource_data="$1"
api_request "POST" "/resources" "$resource_data"
}
update_resource() {
local resource_id="$1"
local resource_data="$2"
api_request "PUT" "/resources/$resource_id" "$resource_data"
}
delete_resource() {
local resource_id="$1"
api_request "DELETE" "/resources/$resource_id"
}
# Beispielverwendung
case "$1" in
"list")
api_request "GET" "/resources" | jq '.'
;;
"get")
get_resource "$2" | jq '.'
;;
"create")
create_resource "$2" | jq '.'
;;
"update")
update_resource "$2" "$3" | jq '.'
;;
"delete")
delete_resource "$2"
;;
*)
echo "Verwendung: $0 {list|get|create|update|delete} [id] [json_data]"
exit 1
;;
esacBei der Verwendung von curl und wget in
Skripten sollten folgende Sicherheitsaspekte beachtet werden:
Behandlung von Anmeldedaten: Speichern Sie Passwörter niemals im Klartext in Skripten. Verwenden Sie stattdessen Umgebungsvariablen, sichere Speicher oder Konfigurationsdateien mit eingeschränkten Berechtigungen.
Zertifikatsprüfung: Vermeiden Sie
-k oder --no-check-certificate in
Produktionsumgebungen. Eine deaktivierte Zertifikatsprüfung macht Ihre
Verbindung anfällig für Man-in-the-Middle-Angriffe.
Eingabevalidierung: Überprüfen Sie alle vom Benutzer bereitgestellten Eingaben, die in URLs oder Anfragedaten verwendet werden.
Ausgabevalidierung: Behandeln Sie Antworten von unbekannten oder nicht vertrauenswürdigen Servern mit Vorsicht. Überprüfen Sie Daten, bevor Sie sie weiterverarbeiten.
Ratelimiting-Beachtung: Respektieren Sie die Nutzungsbeschränkungen der APIs, die Sie verwenden, um Sperren zu vermeiden.
Für rechenintensive Operationen mit vielen HTTP-Anfragen:
#!/bin/bash
# URLs zum Abrufen
mapfile -t URLS < urls.txt
# Maximale Anzahl gleichzeitiger Prozesse
MAX_PROCS=10
current_procs=0
for url in "${URLS[@]}"; do
# Warten, wenn die maximale Anzahl erreicht ist
if [[ $current_procs -ge $MAX_PROCS ]]; then
wait -n # Warten auf Beendigung eines Prozesses
((current_procs--))
fi
# Anfrage im Hintergrund starten
(curl -s "$url" > "$(basename "$url").html") &
((current_procs++))
done
# Auf verbleibende Prozesse warten
waitDurch die Kombination von curl, wget und
Shell-Skripting können Sie leistungsstarke Netzwerkanwendungen
erstellen, die HTTP-Anfragen effizient verarbeiten und komplexe Aufgaben
automatisieren. Diese Tools sind unverzichtbar für Systemadministratoren
und Entwickler, die mit Webanwendungen, APIs oder Datentransfers
arbeiten.
Die Integration von APIs und Web-Services in Shell-Skripte ermöglicht die Automatisierung zahlreicher netzwerkbasierter Aufgaben und die Erstellung leistungsfähiger Workflows. In diesem Abschnitt werden wir uns mit den Grundlagen der API-Kommunikation, REST-Prinzipien und der Verarbeitung von Antwortformaten wie JSON und XML befassen.
APIs (Application Programming Interfaces) definieren Schnittstellen, über die verschiedene Softwaresysteme miteinander kommunizieren können. Web-APIs nutzen typischerweise das HTTP-Protokoll und sind in modernen IT-Umgebungen allgegenwärtig.
REST (Representational State Transfer): Ein architektonischer Stil, bei dem Ressourcen durch URIs identifiziert werden und Standard-HTTP-Methoden (GET, POST, PUT, DELETE) zur Manipulation dieser Ressourcen verwendet werden.
SOAP (Simple Object Access Protocol): Ein Protokoll auf XML-Basis, das komplexere Operationen und formale Verträge zwischen Client und Server unterstützt.
GraphQL: Eine moderne Abfragesprache, die es Clients ermöglicht, genau die Daten anzufordern, die sie benötigen.
WebSockets: Ein Protokoll für bidirektionale Kommunikation in Echtzeit.
REST-APIs sind aufgrund ihrer Einfachheit und Standardisierung besonders gut für die Integration in Shell-Skripte geeignet.
# GET: Daten abrufen
curl -s "https://api.example.com/users/123"
# POST: Neue Ressource erstellen
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{"name": "Max Mustermann", "email": "max@example.com"}' \
"https://api.example.com/users"
# PUT: Bestehende Ressource aktualisieren
curl -s -X PUT \
-H "Content-Type: application/json" \
-d '{"name": "Max Meier", "email": "max@example.com"}' \
"https://api.example.com/users/123"
# PATCH: Teilweise Aktualisierung einer Ressource
curl -s -X PATCH \
-H "Content-Type: application/json" \
-d '{"email": "neuemail@example.com"}' \
"https://api.example.com/users/123"
# DELETE: Ressource löschen
curl -s -X DELETE "https://api.example.com/users/123"Die meisten APIs erfordern eine Form der Authentifizierung. Hier sind die gängigsten Methoden:
#!/bin/bash
API_KEY="Ihr_API_Key_hier"
API_ENDPOINT="https://api.example.com/data"
# API-Key als Query-Parameter
curl -s "${API_ENDPOINT}?api_key=${API_KEY}"
# API-Key als Header
curl -s -H "X-API-Key: ${API_KEY}" "${API_ENDPOINT}"#!/bin/bash
# Konfiguration
CLIENT_ID="Ihre_Client_ID"
CLIENT_SECRET="Ihr_Client_Secret"
TOKEN_URL="https://auth.example.com/oauth/token"
API_ENDPOINT="https://api.example.com/protected-resource"
# Token anfordern
token_response=$(curl -s -X POST "${TOKEN_URL}" \
-d "grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}")
# Token extrahieren (erfordert jq für JSON-Verarbeitung)
access_token=$(echo "${token_response}" | jq -r '.access_token')
# API mit Bearer-Token aufrufen
curl -s -H "Authorization: Bearer ${access_token}" "${API_ENDPOINT}"#!/bin/bash
USERNAME="benutzer"
PASSWORD="passwort"
API_ENDPOINT="https://api.example.com/secured-resource"
# Basic Auth mit curl
curl -s -u "${USERNAME}:${PASSWORD}" "${API_ENDPOINT}"
# Alternativ mit Header
auth_header=$(echo -n "${USERNAME}:${PASSWORD}" | base64)
curl -s -H "Authorization: Basic ${auth_header}" "${API_ENDPOINT}"JSON (JavaScript Object Notation) ist das häufigste Datenformat für moderne APIs. Die Verarbeitung von JSON in Bash kann mit verschiedenen Tools erfolgen:
jq ist ein leichtgewichtiger, flexibler JSON-Prozessor
für die Kommandozeile:
#!/bin/bash
# Beispiel: Abrufen von Wetterdaten
API_KEY="Ihr_Wetter_API_Key"
CITY="Berlin"
WEATHER_API="https://api.openweathermap.org/data/2.5/weather?q=${CITY}&units=metric&appid=${API_KEY}"
# API aufrufen und JSON verarbeiten
weather_data=$(curl -s "${WEATHER_API}")
# Extrahieren spezifischer Werte mit jq
temperature=$(echo "${weather_data}" | jq -r '.main.temp')
weather_desc=$(echo "${weather_data}" | jq -r '.weather[0].description')
humidity=$(echo "${weather_data}" | jq -r '.main.humidity')
echo "Wetter in ${CITY}:"
echo "Temperatur: ${temperature}°C"
echo "Beschreibung: ${weather_desc}"
echo "Luftfeuchtigkeit: ${humidity}%"
# Filtern von Arrays
echo "${weather_data}" | jq '.weather[] | {description: .description, icon: .icon}'
# Transformieren von Daten
echo "${weather_data}" | jq '{
city: .name,
country: .sys.country,
temperature: .main.temp,
conditions: .weather[0].main,
wind_speed: .wind.speed
}'Wenn jq nicht verfügbar ist, können Sie auf andere Tools
zurückgreifen:
#!/bin/bash
# API aufrufen
response=$(curl -s "https://api.example.com/data")
# Einfache Textverarbeitung für spezifische Werte
# (Hinweis: Diese Methode ist weniger robust als jq)
name=$(echo "${response}" | grep -o '"name":"[^"]*"' | cut -d'"' -f4)
id=$(echo "${response}" | grep -o '"id":[0-9]*' | cut -d':' -f2)
echo "Name: ${name}, ID: ${id}"
# Alternativ mit Python (falls verfügbar)
python_extract() {
python3 -c "
import json, sys
data = json.loads(sys.stdin.read())
print(data$1)
"
}
echo "${response}" | python_extract "['name']"Obwohl JSON heute häufiger ist, verwenden viele ältere oder unternehmensinterne APIs noch XML:
#!/bin/bash
# XML-API aufrufen
xml_response=$(curl -s "https://api.example.com/xml-endpoint")
# Mit xmllint (aus libxml2-utils) verarbeiten
if command -v xmllint &>/dev/null; then
# XPath-Abfrage verwenden
value=$(echo "${xml_response}" | xmllint --xpath "//root/element/text()" -)
echo "Extrahierter Wert: ${value}"
fi
# Mit grep und sed (einfachere Alternative)
element_value=$(echo "${xml_response}" | grep -o "<element>[^<]*</element>" | sed -e 's/<element>\(.*\)<\/element>/\1/')
echo "Element-Wert: ${element_value}"Das folgende Beispiel zeigt, wie Sie die GitHub REST API in einem Shell-Skript verwenden können:
#!/bin/bash
# Konfiguration
GITHUB_TOKEN="Ihr_GitHub_Token" # Persönliches Access-Token
GITHUB_API="https://api.github.com"
REPO_OWNER="octocat"
REPO_NAME="hello-world"
# Funktion für GitHub API-Aufrufe
github_api() {
local endpoint="$1"
local method="${2:-GET}"
local data="$3"
local headers=(
-H "Authorization: token ${GITHUB_TOKEN}"
-H "Accept: application/vnd.github.v3+json"
)
if [[ -n "${data}" ]]; then
curl -s -X "${method}" "${headers[@]}" -d "${data}" "${GITHUB_API}${endpoint}"
else
curl -s -X "${method}" "${headers[@]}" "${GITHUB_API}${endpoint}"
fi
}
# Repository-Informationen abrufen
repo_info=$(github_api "/repos/${REPO_OWNER}/${REPO_NAME}")
repo_name=$(echo "${repo_info}" | jq -r '.name')
repo_stars=$(echo "${repo_info}" | jq -r '.stargazers_count')
repo_forks=$(echo "${repo_info}" | jq -r '.forks_count')
echo "Repository: ${repo_name}"
echo "Stars: ${repo_stars}"
echo "Forks: ${repo_forks}"
# Offene Issues auflisten
issues=$(github_api "/repos/${REPO_OWNER}/${REPO_NAME}/issues?state=open")
echo -e "\nOffene Issues:"
echo "${issues}" | jq -r '.[] | "- #\(.number): \(.title)"'
# Einen neuen Issue erstellen
create_issue() {
local title="$1"
local body="$2"
local issue_data=$(jq -n \
--arg title "${title}" \
--arg body "${body}" \
'{title: $title, body: $body}')
github_api "/repos/${REPO_OWNER}/${REPO_NAME}/issues" "POST" "${issue_data}"
}
# Beispielaufruf (auskommentiert)
# new_issue=$(create_issue "API Test Issue" "Dieses Issue wurde automatisch erstellt.")
# echo "Neuer Issue erstellt: #$(echo "${new_issue}" | jq -r '.number')"Viele APIs begrenzen die Anzahl der Ergebnisse pro Anfrage und verwenden Paginierung:
#!/bin/bash
# Konfiguration
API_ENDPOINT="https://api.example.com/resources"
API_KEY="Ihr_API_Key"
PER_PAGE=100
# Funktion zum Abrufen aller Seiten
fetch_all_pages() {
local endpoint="$1"
local page=1
local all_results="[]"
while true; do
local url="${endpoint}?page=${page}&per_page=${PER_PAGE}&api_key=${API_KEY}"
local response=$(curl -s "${url}")
# Ergebnisse dieser Seite extrahieren
local items=$(echo "${response}" | jq -r '.items')
local count=$(echo "${items}" | jq 'length')
# Keine weiteren Ergebnisse
if [[ "${count}" -eq 0 ]]; then
break
fi
# Ergebnisse zusammenführen
all_results=$(echo "${all_results}" | jq --argjson new "${items}" '. + $new')
# Nächste Seite
((page++))
done
echo "${all_results}"
}
# Alle Ressourcen abrufen
all_resources=$(fetch_all_pages "${API_ENDPOINT}")
echo "Insgesamt $(echo "${all_resources}" | jq 'length') Ressourcen gefunden."
# Verarbeiten der Ergebnisse
echo "${all_resources}" | jq -r '.[] | .name'Professionelle API-Integrationen erfordern robuste Fehlerbehandlung und Beachtung von Ratenbegrenzungen:
#!/bin/bash
# Konfiguration
API_ENDPOINT="https://api.example.com/data"
MAX_RETRIES=3
RETRY_DELAY=5 # Sekunden
# Funktion für API-Aufrufe mit Fehlerbehandlung
api_request() {
local url="$1"
local retry_count=0
while [[ ${retry_count} -lt ${MAX_RETRIES} ]]; do
# API aufrufen und Statuscode speichern
response=$(curl -s -w "%{http_code}" -o /tmp/api_response.json "${url}")
status_code=$response
# Erfolg
if [[ ${status_code} -ge 200 && ${status_code} -lt 300 ]]; then
cat /tmp/api_response.json
return 0
fi
# Ratenbegrenzung (429 Too Many Requests)
if [[ ${status_code} -eq 429 ]]; then
# Retry-After Header auslesen (falls vorhanden)
retry_after=$(curl -s -I "${url}" | grep -i "retry-after" | awk '{print $2}' | tr -d '\r')
if [[ -n "${retry_after}" ]]; then
sleep "${retry_after}"
else
# Exponentielles Backoff
sleep $((RETRY_DELAY * 2**retry_count))
fi
# Andere Fehler
else
echo "Fehler: API gab Statuscode ${status_code} zurück" >&2
echo "Antwort: $(cat /tmp/api_response.json)" >&2
# Bei bestimmten Fehlern nicht wiederholen
if [[ ${status_code} -eq 400 || ${status_code} -eq 401 || ${status_code} -eq 403 ]]; then
return 1
fi
sleep "${RETRY_DELAY}"
fi
((retry_count++))
done
echo "Maximale Anzahl von Wiederholungen erreicht" >&2
return 1
}
# Verwendung
data=$(api_request "${API_ENDPOINT}")
if [[ $? -eq 0 ]]; then
echo "Daten erfolgreich abgerufen"
echo "${data}" | jq .
else
echo "Fehler beim Abrufen der Daten"
fiFür Langzeitoperationen bieten viele APIs asynchrone Verarbeitungsmethoden:
#!/bin/bash
# Konfiguration
API_BASE="https://api.example.com"
API_KEY="Ihr_API_Key"
POLL_INTERVAL=5 # Sekunden
MAX_POLLS=60 # Maximal 5 Minuten warten
# Starten einer langläufigen Operation
start_job() {
curl -s -X POST \
-H "Authorization: Bearer ${API_KEY}" \
-H "Content-Type: application/json" \
-d '{"parameters": {"input": "data"}}' \
"${API_BASE}/jobs"
}
# Status einer Operation abfragen
check_job_status() {
local job_id="$1"
curl -s -H "Authorization: Bearer ${API_KEY}" \
"${API_BASE}/jobs/${job_id}"
}
# Job starten
job_response=$(start_job)
job_id=$(echo "${job_response}" | jq -r '.id')
echo "Job gestartet mit ID: ${job_id}"
# Polling bis zur Fertigstellung
poll_count=0
while [[ ${poll_count} -lt ${MAX_POLLS} ]]; do
job_status=$(check_job_status "${job_id}")
status=$(echo "${job_status}" | jq -r '.status')
echo "Job-Status: ${status}"
if [[ "${status}" == "completed" ]]; then
result=$(echo "${job_status}" | jq -r '.result')
echo "Job abgeschlossen! Ergebnis: ${result}"
break
elif [[ "${status}" == "failed" ]]; then
error=$(echo "${job_status}" | jq -r '.error')
echo "Job fehlgeschlagen: ${error}" >&2
exit 1
fi
((poll_count++))
sleep "${POLL_INTERVAL}"
done
if [[ ${poll_count} -eq ${MAX_POLLS} ]]; then
echo "Zeitüberschreitung beim Warten auf Jobabschluss" >&2
exit 1
fiFür Testzwecke kann ein einfacher Webhook-Empfänger mit
netcat oder socat eingerichtet werden:
#!/bin/bash
# Einfacher HTTP-Server auf Port 8080
echo "Starte Webhook-Empfänger auf Port 8080..."
process_webhook() {
local request="$1"
local body=$(echo "${request}" | awk 'BEGIN{RS="\r\n\r\n"} {print $0}' | tail -n 1)
echo "Webhook empfangen: ${body}"
# Verarbeitung hier...
if echo "${body}" | jq -e '.event == "completed"' &>/dev/null; then
echo "Job abgeschlossen!"
fi
}
while true; do
response="HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK"
request=$(nc -l 8080)
echo "${response}" | nc -l 8080 &
process_webhook "${request}"
doneKomplexe Automatisierungen erfordern oft die Integration mehrerer APIs:
#!/bin/bash
# Konfiguration
WEATHER_API_KEY="Wetter_API_Key"
SLACK_WEBHOOK_URL="https://hooks.slack.com/services/XXX/YYY/ZZZ"
CITY="Berlin"
# Wetterdaten abrufen
get_weather() {
local city="$1"
curl -s "https://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${WEATHER_API_KEY}"
}
# Nachricht an Slack senden
send_slack_message() {
local message="$1"
curl -s -X POST \
-H "Content-Type: application/json" \
-d "{\"text\":\"${message}\"}" \
"${SLACK_WEBHOOK_URL}"
}
# Wetterwarnung erstellen
create_weather_alert() {
# Wetter abrufen
weather_data=$(get_weather "${CITY}")
# Daten extrahieren
temp=$(echo "${weather_data}" | jq -r '.main.temp')
conditions=$(echo "${weather_data}" | jq -r '.weather[0].main')
# Nachricht formatieren
message="Wetterbericht für ${CITY}: ${temp}°C, ${conditions}"
# Warnungen basierend auf Bedingungen
if (( $(echo "${temp} > 30" | bc -l) )); then
message="${message}\n⚠️ WARNUNG: Extreme Hitze! Bitte viel trinken und Schatten suchen."
elif (( $(echo "${temp} < 0" | bc -l) )); then
message="${message}\n⚠️ WARNUNG: Frost! Bitte auf mögliche Glätte achten."
fi
if [[ "${conditions}" == "Thunderstorm" ]]; then
message="${message}\n⚠️ WARNUNG: Gewitter! Bitte Aktivitäten im Freien einschränken."
elif [[ "${conditions}" == "Rain" && $(echo "${weather_data}" | jq -r '.rain."3h"') > 10 ]]; then
message="${message}\n⚠️ WARNUNG: Starker Regen! Mögliche Überschwemmungsgefahr."
fi
# An Slack senden
send_slack_message "${message}"
}
# Ausführen
create_weather_alertVerwendung von Konfigurationsdateien: Speichern Sie API-Schlüssel und -Endpunkte in separaten Konfigurationsdateien mit restriktiven Berechtigungen.
Tokenablauf berücksichtigen: Implementieren Sie eine Logik zur Erneuerung abgelaufener Tokens.
Fehlerbehandlung: Implementieren Sie robuste Fehlerbehandlung mit Logging und Benachrichtigungen.
Ratenbegrenzungen respektieren: Implementieren Sie Backoff-Strategien, um Ratenbegrenzungen einzuhalten.
Parallele Verarbeitung: Nutzen Sie Hintergrundprozesse für parallele API-Aufrufe, aber mit Begrenzung der gleichzeitigen Anfragen.
Idempotente Operationen: Gestalten Sie Skripte so, dass sie mehrfach ausgeführt werden können, ohne unerwünschte Nebeneffekte zu verursachen.
Caching: Implementieren Sie Caching, um unnötige API-Aufrufe zu vermeiden.
Monitoring: Führen Sie Metriken zu API-Aufrufen und Erfolgs-/Fehlerraten.
Die Integration von APIs in Shell-Skripte erschließt eine enorme Bandbreite an Automatisierungsmöglichkeiten. Von einfachen Datenabfragen bis hin zu komplexen Workflows können Shell-Skripte als effektive Bindemittel zwischen verschiedenen Diensten und Systemen dienen. Durch die Beachtung der Best Practices und den Einsatz der richtigen Tools können selbst komplexe API-Integrationen zuverlässig und wartbar gestaltet werden.
SSH (Secure Shell) ist ein kryptografisches Netzwerkprotokoll, das sichere Kommunikation über unsichere Netzwerke ermöglicht. In Kombination mit Bash-Skripten wird SSH zu einem mächtigen Werkzeug für die Automatisierung von Aufgaben auf entfernten Systemen. Dieser Abschnitt behandelt die Grundlagen der SSH-Automatisierung, die sichere Ausführung von Befehlen auf entfernten Rechnern und fortgeschrittene Techniken für die effiziente Verwaltung verteilter Systeme.
Die grundlegende Syntax für SSH-Verbindungen ist:
ssh [Optionen] [Benutzer@]Hostname [Befehl]Für Automatisierungszwecke sind folgende Optionen besonders nützlich:
# Ausführen eines einzelnen Befehls auf einem entfernten Host
ssh benutzer@server "ls -la /var/log"
# Nicht-interaktiver Modus (vermeidet Hängen bei Problemen)
ssh -n benutzer@server "uptime"
# Batch-Modus (deaktiviert alle Abfragen)
ssh -n -o BatchMode=yes benutzer@server "df -h"
# Verbindungstimeout setzen
ssh -o ConnectTimeout=10 benutzer@server "uptime"Die passwortlose Authentifizierung ist der Schlüssel zur SSH-Automatisierung:
# SSH-Schlüsselpaar generieren (falls noch nicht vorhanden)
ssh-keygen -t ed25519 -C "Automatisierungsschlüssel"
# Öffentlichen Schlüssel auf den Zielserver übertragen
ssh-copy-id benutzer@server
# Alternative, wenn ssh-copy-id nicht verfügbar ist
cat ~/.ssh/id_ed25519.pub | ssh benutzer@server "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"Die Datei ~/.ssh/config kann verwendet werden, um
Verbindungsdetails zu speichern und abzukürzen:
# Host-Alias definieren
Host webserver
HostName 192.168.1.10
User admin
Port 2222
IdentityFile ~/.ssh/webserver_key
ConnectTimeout 10
BatchMode yes
# Muster für mehrere Server
Host app-*
User deployer
IdentityFile ~/.ssh/deployer_key
StrictHostKeyChecking no
Mit dieser Konfiguration können Sie einfach
ssh webserver oder ssh app-1 verwenden, ohne
alle Parameter angeben zu müssen.
#!/bin/bash
# Grundlegende Remote-Befehlsausführung
ssh server "hostname && uptime"
# Umgebungsvariablen festlegen
ssh server "export PATH=/usr/local/bin:\$PATH && which python3"
# Interaktive Befehle vermeiden
ssh -n server "nohup long-running-command > output.log 2>&1 &"#!/bin/bash
# sudo-Befehl auf einem entfernten System ausführen
ssh admin@server "sudo service nginx restart"
# Mit Passwort-Übergabe (vermeiden, wenn möglich)
echo "sudo_password" | ssh admin@server "sudo -S service nginx restart"
# Besser: sudo ohne Passwort für bestimmte Befehle konfigurieren
# (erfordert vorherige Einrichtung der sudoers-Datei)
ssh admin@server "sudo service nginx restart"#!/bin/bash
# Exit-Code vom Remote-Befehl erhalten
ssh server "test -d /var/www/html"
if [ $? -eq 0 ]; then
echo "Verzeichnis existiert"
else
echo "Verzeichnis existiert nicht"
fi
# Alternative mit direkter Prüfung
if ssh server "test -d /var/www/html"; then
echo "Verzeichnis existiert"
else
echo "Verzeichnis existiert nicht"
fi
# Fehlerbehandlung
ssh server "some-command" || {
echo "Fehler bei der Befehlsausführung auf dem Server" >&2
exit 1
}#!/bin/bash
# Methode 1: Skript über die SSH-Verbindung pipen
cat local_script.sh | ssh server "bash -s"
# Methode 2: Skript mit Argumenten übergeben
cat local_script.sh | ssh server "bash -s -- arg1 arg2"
# Methode 3: Skript hochladen und ausführen
scp local_script.sh server:/tmp/
ssh server "chmod +x /tmp/local_script.sh && /tmp/local_script.sh"#!/bin/bash
ssh server bash << 'EOT'
# Dieser Code läuft auf dem Remote-Server
LOG_DIR="/var/log"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
# Verarbeitung auf Verzeichnisebene
cd "$LOG_DIR" || exit 1
for log_file in *.log; do
echo "Verarbeite $log_file"
# Komplexe Verarbeitung hier...
gzip -c "$log_file" > "/backup/${log_file}-${TIMESTAMP}.gz"
done
# Aufräumen
find "$LOG_DIR" -name "*.log" -type f -mtime +7 -delete
echo "Bereinigung abgeschlossen"
EOT#!/bin/bash
# Daten vom Remote-System abrufen und lokal verarbeiten
server_info=$(ssh server "hostname && uptime && df -h")
# Lokale Verarbeitung
server_name=$(echo "$server_info" | head -1)
uptime_info=$(echo "$server_info" | head -2 | tail -1)
disk_usage=$(echo "$server_info" | grep -m 1 "/dev/sda")
echo "Server: $server_name"
echo "Uptime: $uptime_info"
echo "Hauptpartition: $disk_usage"#!/bin/bash
# Datei auf einen Remote-Server hochladen
scp local_file.txt user@server:/path/to/destination/
# Datei von einem Remote-Server herunterladen
scp user@server:/path/to/remote_file.txt local_directory/
# Verzeichnis rekursiv übertragen
scp -r local_directory/ user@server:/path/to/destination/
# Übertragungsgeschwindigkeit begrenzen (KB/s)
scp -l 1000 large_file.iso user@server:/tmp/#!/bin/bash
# SFTP-Befehle in einem Batchmodus ausführen
sftp -b - user@server << EOF
cd /remote/directory
lcd /local/directory
get file1.txt
get file2.txt
put local_file.txt
bye
EOF#!/bin/bash
# Grundlegende Rsync-Übertragung über SSH
rsync -avz -e ssh /local/directory/ user@server:/remote/directory/
# Inkrementelles Backup mit Rsync
rsync -avz --delete -e ssh /local/directory/ user@server:/backup/directory/
# Übertragung mit Bandbreitenbegrenzung
rsync -avz --bwlimit=1000 -e ssh /local/directory/ user@server:/remote/directory/
# Ausschließen bestimmter Dateien
rsync -avz --exclude='*.tmp' --exclude='cache/' -e ssh /local/directory/ user@server:/remote/directory/#!/bin/bash
SERVERS=("web1" "web2" "web3" "db1" "db2")
COMMAND="uptime"
for server in "${SERVERS[@]}"; do
echo "=== Führe Befehl auf $server aus ==="
ssh "$server" "$COMMAND"
done#!/bin/bash
SERVERS=("web1" "web2" "web3" "db1" "db2")
COMMAND="uptime"
MAX_PARALLEL=3
running=0
for server in "${SERVERS[@]}"; do
# Maximale Anzahl paralleler Prozesse begrenzen
if [[ $running -ge $MAX_PARALLEL ]]; then
wait -n # Warten auf Beendigung eines Prozesses
running=$((running - 1))
fi
# Befehl im Hintergrund ausführen
(
echo "=== Ausführung auf $server ==="
if ssh -o ConnectTimeout=5 "$server" "$COMMAND"; then
echo "=== $server: Erfolgreich ==="
else
echo "=== $server: Fehler ($?) ===" >&2
fi
) &
running=$((running + 1))
done
# Auf verbleibende Prozesse warten
wait
echo "Alle Befehle abgeschlossen"#!/bin/bash
SERVERS=("web1" "web2" "web3" "db1" "db2")
RESULTS_DIR="/tmp/server_results"
mkdir -p "$RESULTS_DIR"
# Funktion zur Ausführung auf einem Server
run_on_server() {
local server="$1"
local output_file="$RESULTS_DIR/$server.out"
echo "Starte Ausführung auf $server..."
# Mehrere Befehle auf dem Remote-Server ausführen
ssh -o ConnectTimeout=5 "$server" << 'EOT' > "$output_file" 2>&1
hostname
uptime
df -h | grep -v tmpfs
free -m
grep -c processor /proc/cpuinfo
EOT
local status=$?
if [[ $status -eq 0 ]]; then
echo "Ausführung auf $server erfolgreich abgeschlossen"
else
echo "Fehler bei der Ausführung auf $server (Exit-Code: $status)" >&2
fi
return $status
}
# Parallel auf allen Servern ausführen
for server in "${SERVERS[@]}"; do
run_on_server "$server" &
done
# Auf alle Hintergrundprozesse warten
wait
# Ergebnisse zusammenfassen
echo -e "\n=== Zusammenfassung ===\n"
for server in "${SERVERS[@]}"; do
result_file="$RESULTS_DIR/$server.out"
if [[ -f "$result_file" ]]; then
hostname=$(head -1 "$result_file")
disk_usage=$(grep -m 1 '/' "$result_file" | awk '{print $5}')
load=$(grep -o 'load average:.*' "$result_file" | cut -d: -f2 | tr -d ',')
cpu_count=$(tail -1 "$result_file")
echo "$server ($hostname):"
echo " - Festplattenbelegung: $disk_usage"
echo " - Load: $load"
echo " - CPUs: $cpu_count"
else
echo "$server: Keine Ergebnisse (Verbindungsfehler?)"
fi
done#!/bin/bash
# Lokales Port-Forwarding einrichten
# Lokaler Port 8080 wird an den Port 80 des Remote-Servers weitergeleitet
ssh -L 8080:localhost:80 -N -f user@server
# Überprüfen, ob der Tunnel läuft
if ps aux | grep "ssh -L" | grep -v grep > /dev/null; then
echo "SSH-Tunnel ist aktiv"
else
echo "SSH-Tunnel konnte nicht eingerichtet werden"
fi
# Skript, das den Tunnel nutzt
curl http://localhost:8080/
# Tunnel beenden (alle passenden SSH-Prozesse)
pkill -f "ssh -L 8080:localhost:80"#!/bin/bash
# Entferntes Port-Forwarding einrichten
# Port 8080 auf dem Remote-Server wird an den lokalen Port 80 weitergeleitet
ssh -R 8080:localhost:80 -N -f user@server
# Tunnel-Management
PID_FILE="/tmp/ssh_tunnel.pid"
# Tunnel starten
start_tunnel() {
ssh -R 8080:localhost:80 -N -f user@server
echo $! > "$PID_FILE"
echo "Tunnel gestartet mit PID $(cat "$PID_FILE")"
}
# Tunnel stoppen
stop_tunnel() {
if [[ -f "$PID_FILE" ]]; then
kill $(cat "$PID_FILE") 2>/dev/null
rm "$PID_FILE"
echo "Tunnel beendet"
else
echo "Kein aktiver Tunnel gefunden"
fi
}
# Tunnelstatus überprüfen
check_tunnel() {
if [[ -f "$PID_FILE" ]] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
echo "Tunnel läuft mit PID $(cat "$PID_FILE")"
else
echo "Tunnel läuft nicht"
fi
}#!/bin/bash
# SOCKS-Proxy auf Port 1080 einrichten
ssh -D 1080 -q -C -N -f user@server
# Überprüfen, ob der Proxy läuft
netstat -tulpn | grep 1080
# Beispiel: curl über den SOCKS-Proxy
curl --socks5 localhost:1080 http://example.com/#!/bin/bash
KEY_TYPE="ed25519"
KEY_NAME="automation_key"
KEY_FILE="$HOME/.ssh/${KEY_NAME}"
KEY_COMMENT="Automatisch generierter Schlüssel für $(whoami)@$(hostname)"
# Prüfen, ob der Schlüssel bereits existiert
if [[ -f "${KEY_FILE}" ]]; then
echo "Schlüssel existiert bereits: ${KEY_FILE}"
exit 0
fi
# Schlüssel ohne Passphrase generieren
ssh-keygen -t "$KEY_TYPE" -f "$KEY_FILE" -N "" -C "$KEY_COMMENT"
# Berechtigungen korrigieren
chmod 600 "${KEY_FILE}"
chmod 644 "${KEY_FILE}.pub"
echo "Schlüssel erfolgreich generiert:"
echo "Private Key: ${KEY_FILE}"
echo "Public Key: ${KEY_FILE}.pub"
# Optional: Öffentlichen Schlüssel anzeigen
echo -e "\nÖffentlicher Schlüssel:"
cat "${KEY_FILE}.pub"#!/bin/bash
KEY_FILE="$HOME/.ssh/automation_key.pub"
SERVERS=("web1" "web2" "db1" "db2")
# Prüfen, ob der öffentliche Schlüssel existiert
if [[ ! -f "$KEY_FILE" ]]; then
echo "Fehler: Öffentlicher Schlüssel nicht gefunden: $KEY_FILE" >&2
exit 1
fi
# Schlüssel auf jeden Server kopieren
for server in "${SERVERS[@]}"; do
echo "Kopiere Schlüssel auf $server..."
# Methode 1: Mit ssh-copy-id
if command -v ssh-copy-id >/dev/null; then
ssh-copy-id -i "$KEY_FILE" "user@$server"
else
# Methode 2: Manuelles Kopieren
cat "$KEY_FILE" | ssh "user@$server" "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
fi
# Überprüfen, ob der Schlüssel funktioniert
if ssh -i "${KEY_FILE%.pub}" -o BatchMode=yes "user@$server" "echo 'Schlüsseltest erfolgreich'"; then
echo "✓ Schlüssel auf $server erfolgreich installiert"
else
echo "✗ Fehler beim Testen des Schlüssels auf $server" >&2
fi
done#!/bin/bash
# SSH-Agent starten, falls noch nicht aktiv
start_ssh_agent() {
if [[ -z "$SSH_AUTH_SOCK" ]]; then
eval $(ssh-agent -s)
echo "SSH-Agent gestartet mit PID $SSH_AGENT_PID"
else
echo "SSH-Agent läuft bereits mit Socket $SSH_AUTH_SOCK"
fi
}
# Schlüssel zum SSH-Agent hinzufügen
add_key_to_agent() {
local key_file="$1"
if [[ ! -f "$key_file" ]]; then
echo "Fehler: Schlüsseldatei nicht gefunden: $key_file" >&2
return 1
fi
# Prüfen, ob der Schlüssel bereits hinzugefügt wurde
if ssh-add -l | grep -q "$(ssh-keygen -lf "$key_file" | awk '{print $2}')"; then
echo "Schlüssel ist bereits im SSH-Agent"
else
ssh-add "$key_file"
echo "Schlüssel hinzugefügt: $key_file"
fi
}
# Verwendung
start_ssh_agent
add_key_to_agent "$HOME/.ssh/automation_key"
# Automatisierungsbefehle mit SSH-Agent ausführen
ssh server "uptime"In der authorized_keys-Datei können Schlüssel mit
Einschränkungen versehen werden:
# Beispiel für einen Eintrag in ~/.ssh/authorized_keys mit Einschränkungen
# Nur bestimmte Befehle erlauben
command="uptime" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... automation@host
# IP-Beschränkungen
from="192.168.1.*" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... automation@host
# Kombination mehrerer Einschränkungen
command="df -h",from="10.0.0.*",no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... automation@host#!/bin/bash
KEY_FILE="$HOME/.ssh/automation_key.pub"
SERVER="target-server"
ALLOWED_COMMANDS=("uptime" "df -h" "/usr/local/sbin/backup.sh")
ALLOWED_NETWORKS=("192.168.1.*" "10.0.0.*")
# Öffentlichen Schlüssel einlesen
if [[ ! -f "$KEY_FILE" ]]; then
echo "Fehler: Öffentlicher Schlüssel nicht gefunden: $KEY_FILE" >&2
exit 1
fi
public_key=$(cat "$KEY_FILE")
# Einschränkungen erstellen
restrictions=""
# Netzwerk-Einschränkungen
network_restriction="from=\"$(IFS=,; echo "${ALLOWED_NETWORKS[*]}")\""
restrictions="${restrictions}${network_restriction},"
# Befehlseinschränkungen, wenn spezifiziert
if [[ ${#ALLOWED_COMMANDS[@]} -gt 0 ]]; then
# Mehrere Befehle mit SSH-Wrapper-Skript erlauben
ssh "user@$SERVER" "cat > /tmp/ssh-wrapper.sh << 'EOF'
#!/bin/bash
# SSH-Befehlswrapper
cmd=\$SSH_ORIGINAL_COMMAND
case \"\$cmd\" in
$(for cmd in "${ALLOWED_COMMANDS[@]}"; do echo " \"$cmd\") $cmd ;;"; done)
*) echo \"Befehl nicht erlaubt: \$cmd\" >&2; exit 1 ;;
esac
EOF
chmod +x /tmp/ssh-wrapper.sh
sudo mv /tmp/ssh-wrapper.sh /usr/local/bin/ssh-wrapper.sh"
restrictions="${restrictions}command=\"/usr/local/bin/ssh-wrapper.sh\","
fi
# Weitere Einschränkungen
restrictions="${restrictions}no-port-forwarding,no-X11-forwarding,no-agent-forwarding"
# Schlüssel mit Einschränkungen hinzufügen
restricted_key="$restrictions $public_key"
echo "Installiere eingeschränkten Schlüssel auf $SERVER..."
echo "$restricted_key" | ssh "user@$SERVER" "cat >> ~/.ssh/authorized_keys"
echo "Schlüssel mit folgenden Einschränkungen installiert:"
echo "$restrictions"#!/bin/bash
# Überwachung aktiver SSH-Sitzungen auf einem Server
SERVER="monitoring-server"
# SSH-Sitzungen abfragen
ssh_sessions=$(ssh "admin@$SERVER" "who | grep -i ssh")
echo "Aktive SSH-Sitzungen auf $SERVER:"
echo "$ssh_sessions"
# Optional: Verdächtige Aktivitäten überprüfen
ssh "admin@$SERVER" "grep 'Failed password' /var/log/auth.log | tail -10"
# Sitzungen mit ungewöhnlicher Dauer identifizieren
ssh "admin@$SERVER" "w -h | awk '{print \$1, \$2, \$3, \$4}' | sort -k 4" | while read user from login idle; do
# Idle-Zeit in Minuten konvertieren
if [[ "$idle" == *"days"* ]]; then
echo "WARNUNG: Benutzer $user von $from ist seit $idle inaktiv!"
fi
done#!/bin/bash
SERVER="frequent-access-server"
SOCKET_DIR="/tmp/ssh_mux"
SOCKET_FILE="$SOCKET_DIR/$SERVER"
# Socket-Verzeichnis erstellen
mkdir -p "$SOCKET_DIR"
chmod 700 "$SOCKET_DIR"
# Master-Verbindung öffnen
echo "Öffne Master-Verbindung zu $SERVER..."
ssh -M -S "$SOCKET_FILE" -o ControlPersist=10m "$SERVER" "echo 'Master-Verbindung hergestellt'"
# Funktion zum Ausführen von Befehlen über die Master-Verbindung
run_ssh_command() {
local cmd="$1"
echo "Führe aus: $cmd"
ssh -S "$SOCKET_FILE" "$SERVER" "$cmd"
}
# Mehrere Befehle ausführen (sehr schnell, da eine Verbindung wiederverwendet wird)
run_ssh_command "uptime"
run_ssh_command "df -h"
run_ssh_command "free -m"
# Master-Verbindung schließen
echo "Schließe Master-Verbindung..."
ssh -S "$SOCKET_FILE" -O exit "$SERVER"#!/bin/bash
# Direkter Zugriff über einen Jumphost
ssh -J jumphost.example.com internal-server.local "uptime"
# Alternative mit SSH-Konfiguration in ~/.ssh/config:
# Host internal-server
# HostName internal-server.local
# User admin
# ProxyJump jumphost.example.com
# Mehrere Jumphosts verwenden
ssh -J jumphost1.example.com,jumphost2.example.com internal-server.local
# Dateiübertragung über einen Jumphost
scp -J jumphost.example.com local_file.txt internal-server.local:/destination/path/#!/bin/bash
# Konfiguration
APP_NAME="myapp"
APP_VERSION="1.2.3"
SERVERS=("web1" "web2" "web3")
DEPLOY_USER="deployer"
DEPLOY_PATH="/var/www/$APP_NAME"
PACKAGE_FILE="${APP_NAME}-${APP_VERSION}.tar.gz"
BACKUP_DIR="/var/backups/$APP_NAME"
# Fehlerbehandlung
set -e # Skript bei Fehlern beenden
trap 'echo "Deployment fehlgeschlagen!"; exit 1' ERR
echo "=== Deployment von $APP_NAME v$APP_VERSION startet ==="
# Paket auf jeden Server kopieren
for server in "${SERVERS[@]}"; do
echo "Deployment auf $server..."
# SSH-Session für mehrere Befehle verwenden
ssh "$DEPLOY_USER@$server" << EOF
# Verzeichnis vorbereiten
if [[ ! -d "$DEPLOY_PATH" ]]; then
mkdir -p "$DEPLOY_PATH"
fi
# Backup erstellen
if [[ -d "$DEPLOY_PATH/current" ]]; then
echo "Erstelle Backup..."
mkdir -p "$BACKUP_DIR"
cp -a "$DEPLOY_PATH/current" "$BACKUP_DIR/$APP_NAME-$(date +%Y%m%d-%H%M%S)"
# Ältere Backups bereinigen
find "$BACKUP_DIR" -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
fi
# Verzeichnis für neue Version erstellen
mkdir -p "$DEPLOY_PATH/releases/$APP_VERSION"
EOF
# Paket übertragen
echo "Übertrage Paket auf $server..."
scp "$PACKAGE_FILE" "$DEPLOY_USER@$server:/tmp/"
# Paket entpacken und installieren
ssh "$DEPLOY_USER@$server" << EOF
# Paket entpacken
tar -xzf "/tmp/$PACKAGE_FILE" -C "$DEPLOY_PATH/releases/$APP_VERSION"
rm "/tmp/$PACKAGE_FILE"
# Symlink aktualisieren
if [[ -L "$DEPLOY_PATH/current" ]]; then
rm "$DEPLOY_PATH/current"
fi
ln -sf "$DEPLOY_PATH/releases/$APP_VERSION" "$DEPLOY_PATH/current"
# Berechtigungen anpassen
find "$DEPLOY_PATH/current" -type f -exec chmod 644 {} \;
find "$DEPLOY_PATH/current" -type d -exec chmod 755 {} \;
# Anwendungsspezifische Aktionen
if [[ -f "$DEPLOY_PATH/current/scripts/post-deploy.sh" ]]; then
echo "Führe Post-Deployment-Skript aus..."
cd "$DEPLOY_PATH/current" && ./scripts/post-deploy.sh
fi
# Service neustarten
echo "Starte Anwendungsdienst neu..."
sudo systemctl restart "$APP_NAME"
# Status überprüfen
sleep 2
if sudo systemctl is-active "$APP_NAME" > /dev/null; then
echo "Dienst erfolgreich gestartet"
else
echo "FEHLER: Dienst konnte nicht gestartet werden!"
exit 1
fi
EOF
echo "Deployment auf $server abgeschlossen"
done
echo "=== Deployment erfolgreich abgeschlossen ==="Verwenden Sie dedizierten SSH-Schlüssel für Automatisierungsaufgaben, nicht Ihre persönlichen Schlüssel.
Beschränken Sie Schlüsselfunktionalität durch
Einschränkungen in der authorized_keys-Datei.
Implementieren Sie Timeouts für SSH-Verbindungen, um hängende Skripte zu vermeiden.
Prüfen Sie Rückgabecodes von SSH-Befehlen, um Fehler zu erkennen.
Protokollieren Sie Aktivitäten für Audit-Zwecke und zur Fehlersuche.
Verwenden Sie SSH-Konfigurationsdateien für wiederholte Verbindungen.
Verwenden Sie ControlMaster/ControlPersist für mehrere Befehle auf demselben Host.
Implementieren Sie Fehlerbehandlung und Wiederholungslogik für instabile Netzwerke.
Beschränken Sie den Zugriff auf Skripte mit sensiblen Informationen oder Schlüsseln.
Überwachen Sie SSH-Aktivitäten auf verdächtige Muster.
Die Kombination aus SSH und Bash-Skripten bildet eine leistungsstarke Plattform für die Automatisierung von Netzwerkoperationen, Systemadministration und Deployment-Prozessen. Durch die Beachtung der Sicherheitsrichtlinien und bewährten Praktiken können Sie zuverlässige und sichere Automatisierungslösungen implementieren, die über verschiedene Netzwerkumgebungen hinweg funktionieren.
Der SSH-Agent ist ein Hintergrundprogramm, das private SSH-Schlüssel sicher im Speicher hält und die Authentifizierung verwaltet. Er ermöglicht die Verwendung passwortgeschützter Schlüssel in Automatisierungsskripten, ohne dass das Passwort jedes Mal eingegeben werden muss, und erhöht so sowohl die Sicherheit als auch die Benutzerfreundlichkeit.
# SSH-Agent starten
eval $(ssh-agent)
# Alternativ mit Lebensdauer begrenzen (in Sekunden)
eval $(ssh-agent -t 3600) # Agent läuft für 1 Stunde
# Schlüssel zum Agenten hinzufügen
ssh-add ~/.ssh/id_ed25519
# Passwortgeschützten Schlüssel hinzufügen (interaktive Passwortabfrage)
ssh-add ~/.ssh/secure_key
# Schlüssel mit bestimmtem Pfad hinzufügen
ssh-add /path/to/specific_key
# Alle Standardschlüssel hinzufügen
ssh-add# Alle geladenen Schlüssel anzeigen (Fingerabdrücke)
ssh-add -l
# Detaillierte Ausgabe mit vollständigem Pfad
ssh-add -L
# Spezifischen Schlüssel entfernen
ssh-add -d ~/.ssh/specific_key
# Alle Schlüssel entfernen
ssh-add -D
# SSH-Agent beenden
ssh-agent -k#!/bin/bash
# Funktion zur Verwaltung des SSH-Agents
setup_ssh_agent() {
# Prüfen, ob bereits ein Agent läuft
if [[ -z "$SSH_AUTH_SOCK" ]]; then
echo "Starte neuen SSH-Agent..."
eval $(ssh-agent)
echo "SSH-Agent gestartet mit PID $SSH_AGENT_PID"
# PID für späteres Beenden speichern
echo "$SSH_AGENT_PID" > /tmp/ssh_agent_pid
else
echo "Verwende existierenden SSH-Agent mit Socket $SSH_AUTH_SOCK"
fi
# Schlüssel hinzufügen, falls noch nicht geladen
if ! ssh-add -l | grep -q "$(ssh-keygen -lf ~/.ssh/automation_key | awk '{print $2}')"; then
echo "Füge Automatisierungsschlüssel hinzu..."
ssh-add ~/.ssh/automation_key
fi
}
# Funktion zum Beenden des Agenten
cleanup_ssh_agent() {
if [[ -f /tmp/ssh_agent_pid ]]; then
local agent_pid=$(cat /tmp/ssh_agent_pid)
echo "Beende SSH-Agent (PID $agent_pid)..."
kill "$agent_pid"
rm /tmp/ssh_agent_pid
fi
}
# Agent einrichten
setup_ssh_agent
# Automatisierungsaufgaben ausführen
echo "Führe SSH-Befehle mit Agent-Unterstützung aus..."
ssh server1 "uptime"
ssh server2 "df -h"
# Bei Skript-Ende Agent beenden
trap cleanup_ssh_agent EXIT#!/bin/bash
AGENT_FILE="$HOME/.ssh/agent_info"
# Funktion zum Starten oder Wiederverwenden eines Agenten
start_or_reuse_agent() {
# Prüfen, ob eine Agent-Datei existiert
if [[ -f "$AGENT_FILE" ]]; then
echo "Versuche, bestehenden Agent zu laden..."
source "$AGENT_FILE"
# Prüfen, ob der Agent noch läuft
if kill -0 "$SSH_AGENT_PID" 2>/dev/null; then
echo "Bestehender SSH-Agent läuft mit PID $SSH_AGENT_PID"
# Testen, ob der Agent funktioniert
if ssh-add -l &>/dev/null; then
echo "SSH-Agent ist funktionsfähig"
return 0
else
echo "SSH-Agent nicht funktionsfähig, starte neu..."
fi
else
echo "SSH-Agent mit PID $SSH_AGENT_PID nicht mehr aktiv"
fi
fi
# Neuen Agenten starten
echo "Starte neuen SSH-Agent..."
ssh-agent > "$AGENT_FILE"
chmod 600 "$AGENT_FILE"
source "$AGENT_FILE"
echo "Neuer SSH-Agent gestartet mit PID $SSH_AGENT_PID"
# Schlüssel hinzufügen
echo "Füge Schlüssel hinzu..."
ssh-add ~/.ssh/automation_key
return 0
}
# Verwendung
start_or_reuse_agent
# Automatisierungstasks ausführen
ssh server "uptime"Agent-Forwarding ermöglicht es, den lokalen SSH-Agenten über mehrere Hops hinweg zu verwenden:
# SSH-Konfiguration für Agent-Forwarding in ~/.ssh/config
Host jumphost
HostName jumphost.example.com
ForwardAgent yes
Host internal
HostName internal.example.local
ProxyJump jumphost
ForwardAgent yes#!/bin/bash
# Sicheres Skript für Agent-Forwarding
# HINWEIS: Agent-Forwarding sollte nur mit vertrauenswürdigen Servern verwendet werden
# Ensure agent is running
eval $(ssh-agent)
ssh-add ~/.ssh/id_ed25519
# Mehrstufige Verbindung mit Agent-Forwarding
echo "Verbinde mit Zielserver über Jumphost..."
ssh -A jumphost ssh targetserver "git clone git@github.com:user/private-repo.git"
# Alternative mit ProxyJump
ssh -J jumphost -A targetserver "git clone git@github.com:user/private-repo.git"
# Agent beenden
ssh-agent -kDer SSH-Agent bietet Komfort, kann aber bei unsachgemäßer Verwendung Sicherheitsrisiken darstellen:
Begrenzte Lebensdauer: Setzen Sie eine zeitliche
Begrenzung für den Agenten mit -t (Sekunden).
Eingeschränkte Schlüsselverwendung: Verwenden
Sie ssh-add -c, um Bestätigungen für jede
Schlüsselverwendung zu fordern.
Vorsicht bei Agent-Forwarding: Verwenden Sie Agent-Forwarding nur mit vertrauenswürdigen Servern, da der Root-Benutzer des Zielservers auf Ihren Agenten zugreifen kann.
Dedizierte Agenten: Verwenden Sie für Automatisierungsaufgaben einen separaten Agenten mit eingeschränkten Schlüsseln.
Überwachung: Protokollieren Sie die Verwendung des Agenten für Audit-Zwecke.
#!/bin/bash
# Beispiel: Eingeschränkter SSH-Agent für Automatisierung
# Dedizierter Agent nur für die Dauer des Skripts
eval $(ssh-agent)
# Bestätigungsaufforderung für Schlüsselverwendung aktivieren
# (Beachten Sie: Dies funktioniert nur bei interaktiven Sitzungen)
ssh-add -c ~/.ssh/automation_key
# Alternativ: Zeitlich begrenzter Agent
eval $(ssh-agent -t 1800) # 30 Minuten
ssh-add ~/.ssh/automation_key
# Ausführung der automatisierten Aufgaben
ssh server1 "backup_script"
# Agent beenden
ssh-agent -kDer SSH-Agent ist ein unverzichtbares Werkzeug für die SSH-Automatisierung, insbesondere wenn passwortgeschützte Schlüssel verwendet werden oder wenn komplexe mehrstufige Verbindungen erforderlich sind. Durch die richtige Konfiguration und Verwendung des Agenten lässt sich ein gutes Gleichgewicht zwischen Sicherheit und Benutzerfreundlichkeit erzielen.
Netcat (oft abgekürzt als nc) ist ein vielseitiges
Netzwerkdienstprogramm, das als “Schweizer Taschenmesser” für
TCP/IP-Verbindungen gilt. Es kann als einfacher Server oder Client
fungieren, Daten über Netzwerkverbindungen übertragen und empfangen und
ist ein leistungsstarkes Werkzeug für Netzwerktests, Debugging und sogar
einfache Client-Server-Anwendungen. In diesem Abschnitt werden wir die
grundlegenden Funktionen von netcat und deren Integration in
Bash-Skripte untersuchen.
Netcat ist in fast allen Linux-Distributionen verfügbar und kann in zwei Hauptmodi betrieben werden: als Client oder als Server.
# Verbindung zu einem Server herstellen
nc server.example.com 80
# Verbindung mit Timeout (in Sekunden)
nc -w 5 server.example.com 80
# Verbindung zu UDP-Port
nc -u server.example.com 53# Auf TCP-Port 12345 lauschen
nc -l 12345
# Auf spezifischer IP-Adresse und Port lauschen
nc -l 192.168.1.10 12345
# Auf UDP-Port lauschen
nc -u -l 12345Netcat kann einfach für die Übertragung von Daten zwischen Systemen verwendet werden:
# Auf Empfängerseite (Server)
nc -l 12345 > empfangene_datei.txt
# Auf Senderseite (Client)
nc server.example.com 12345 < zu_sendende_datei.txt# Auf Empfängerseite
nc -l 12345 | tar xzf -
# Auf Senderseite
tar czf - verzeichnis/ | nc server.example.com 12345Netcat kann für einfache bidirektionale Kommunikation genutzt werden:
# Server-Seite
nc -l 12345
# Client-Seite
nc server.example.com 12345Nachdem die Verbindung hergestellt ist, kann jede Seite Nachrichten eingeben, die auf der anderen Seite angezeigt werden.
Netcat ist ein wertvolles Werkzeug für das Debugging von Netzwerkdiensten:
# HTTP-Anfrage manuell senden
echo -e "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n" | nc example.com 80
# Port-Scan mit Netcat
for port in {20..25}; do
nc -zv server.example.com $port 2>&1 | grep succeeded
done
# Banner-Grabbing (Diensterkennung)
echo "" | nc -v -n -w 1 192.168.1.1 22Netcat kann in einigen Varianten mit der Option -k
verwendet werden, um persistente Verbindungen aufrechtzuerhalten:
# Persistenter Server mit GNU Netcat
nc -k -l 12345
# Alternativ mit traditionellem Netcat über eine Schleife
while true; do
echo "Server gestartet auf Port 12345..."
nc -l 12345
echo "Verbindung geschlossen, starte neu..."
sleep 1
doneEin minimalistischer HTTP-Server kann mit netcat implementiert werden:
#!/bin/bash
PORT=8080
RESPONSE="HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html><body><h1>Hallo von Netcat-Webserver</h1></body></html>\r\n"
while true; do
echo -e "$RESPONSE" | nc -l -p $PORT
echo "Anfrage beantwortet"
doneFür einen etwas robusteren Server mit Datei-Serving:
#!/bin/bash
PORT=8080
WEBROOT="/var/www/html"
while true; do
echo "Warte auf Verbindungen auf Port $PORT..."
REQUEST=$(nc -l $PORT)
# HTTP-Anfrage parsen
RESOURCE=$(echo "$REQUEST" | head -n 1 | awk '{print $2}')
echo "Anfrage für Ressource: $RESOURCE"
# Standardseite, wenn / angefordert wird
if [[ "$RESOURCE" == "/" ]]; then
RESOURCE="/index.html"
fi
# Vollständiger Pfad zur angeforderten Datei
FILEPATH="${WEBROOT}${RESOURCE}"
# Prüfen, ob Datei existiert und lesbar ist
if [[ -f "$FILEPATH" && -r "$FILEPATH" ]]; then
# MIME-Typ bestimmen
CONTENT_TYPE=$(file --mime-type -b "$FILEPATH")
# HTTP-Antwort senden
{
echo -e "HTTP/1.1 200 OK\r"
echo -e "Content-Type: $CONTENT_TYPE\r"
echo -e "\r"
cat "$FILEPATH"
} | nc -l $PORT
else
# 404 Not Found
{
echo -e "HTTP/1.1 404 Not Found\r"
echo -e "Content-Type: text/html\r"
echo -e "\r"
echo -e "<html><body><h1>404 Not Found</h1><p>Die angeforderte Ressource $RESOURCE wurde nicht gefunden.</p></body></html>\r"
} | nc -l $PORT
fi
echo "Anfrage beantwortet"
sleep 1
doneEin einfacher TCP-Proxy kann mit netcat implementiert werden:
#!/bin/bash
LOCAL_PORT=8080
REMOTE_HOST="example.com"
REMOTE_PORT=80
echo "Starte Proxy auf Port $LOCAL_PORT zu $REMOTE_HOST:$REMOTE_PORT"
# Option 1: Mit mkfifo (effizient)
FIFO="/tmp/proxy_fifo"
mkfifo "$FIFO"
while true; do
nc -l $LOCAL_PORT < "$FIFO" | nc $REMOTE_HOST $REMOTE_PORT > "$FIFO"
done
rm -f "$FIFO"
# Option 2: Alternative mit separaten Prozessen
# while true; do
# nc -l $LOCAL_PORT | tee /tmp/proxy_out | nc $REMOTE_HOST $REMOTE_PORT | tee /tmp/proxy_in | nc -l $LOCAL_PORT
# doneNetcat kann für einfache Netzwerküberwachung verwendet werden:
#!/bin/bash
# Einfache Dienstverfügbarkeitsüberwachung
HOSTS=("web.example.com:80" "db.example.com:3306" "mail.example.com:25")
LOG_FILE="/var/log/service_monitor.log"
check_service() {
local host_port="$1"
local host=$(echo "$host_port" | cut -d: -f1)
local port=$(echo "$host_port" | cut -d: -f2)
# Timeout von 3 Sekunden
if nc -z -w 3 "$host" "$port" 2>/dev/null; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - $host:$port ist ERREICHBAR" >> "$LOG_FILE"
return 0
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - $host:$port ist NICHT ERREICHBAR" >> "$LOG_FILE"
return 1
fi
}
# Hauptfunktion
echo "=== Dienstverfügbarkeitsüberwachung gestartet $(date) ===" >> "$LOG_FILE"
for host_port in "${HOSTS[@]}"; do
if ! check_service "$host_port"; then
# Hier könnte eine Benachrichtigung erfolgen
echo "WARNUNG: $host_port ist nicht erreichbar!" >&2
fi
done#!/bin/bash
# Sicherer Netcat-Server mit Autologout nach 60 Sekunden Inaktivität
# und Begrenzung der max. Verbindungszeit auf 5 Minuten
PORT=12345
MAX_TIME=300 # 5 Minuten in Sekunden
TIMEOUT=60 # 60 Sekunden Inaktivitätstimeout
echo "Starte sicheren Netcat-Server auf Port $PORT..."
# PID des Netcat-Prozesses speichern
nc -l $PORT &
NC_PID=$!
# Timeout für Inaktivität
( sleep $TIMEOUT && kill -0 $NC_PID 2>/dev/null && { echo "Timeout wegen Inaktivität"; kill $NC_PID; } ) &
TIMEOUT_PID=$!
# Maximale Verbindungszeit
( sleep $MAX_TIME && kill -0 $NC_PID 2>/dev/null && { echo "Maximale Verbindungszeit erreicht"; kill $NC_PID; } ) &
MAXTIME_PID=$!
# Warten auf Beendigung des Netcat-Prozesses
wait $NC_PID
# Timeout-Prozesse beenden
kill $TIMEOUT_PID 2>/dev/null
kill $MAXTIME_PID 2>/dev/null
echo "Netcat-Server beendet"Hinweis: Die folgenden Beispiele dienen ausschließlich Bildungszwecken und sollten nur in kontrollierten Umgebungen mit angemessenen Sicherheitsmaßnahmen verwendet werden.
# Auf der Server-Seite (empfangender Host):
nc -l 12345 -e /bin/bash
# Alternativ, wenn -e nicht verfügbar ist:
mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | nc -l 12345 > /tmp/f; rm /tmp/f
# Auf der Client-Seite:
nc server.example.com 12345#!/bin/bash
# Backup-Skript mit Netcat-basierter Fortschrittsüberwachung
SOURCE_DIR="/home/user/data"
REMOTE_HOST="backup.example.com"
REMOTE_PORT=12345
BACKUP_NAME="backup-$(date +%Y%m%d).tar.gz"
# Größe der zu sichernden Daten ermitteln
TOTAL_SIZE=$(du -sb "$SOURCE_DIR" | awk '{print $1}')
# Status-Server starten
status_server() {
local port=$1
# Einfacher HTTP-Server, der den Fortschritt zurückgibt
while true; do
echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nBackup-Fortschritt: $PROGRESS von $TOTAL_SIZE Bytes ($PERCENT%)\r\n" | nc -l $port
done
}
# Fortschrittsvariablen
PROGRESS=0
PERCENT=0
# Status-Server im Hintergrund starten
status_server 8080 &
STATUS_PID=$!
# Pipe für tar-Ausgabe
mkfifo /tmp/backup_pipe
exec 3<> /tmp/backup_pipe
# Fortschritt überwachen
(
while read -r line; do
# Fortschritt aktualisieren (vereinfacht)
PROGRESS=$((PROGRESS + 1024))
PERCENT=$((PROGRESS * 100 / TOTAL_SIZE))
if [[ $((PROGRESS % 10485760)) -eq 0 ]]; then # Alle 10MB aktualisieren
echo "Fortschritt: $PERCENT% ($PROGRESS von $TOTAL_SIZE Bytes)"
fi
done < /tmp/backup_pipe
) &
MONITOR_PID=$!
# Backup durchführen
echo "Starte Backup von $SOURCE_DIR nach $REMOTE_HOST:$REMOTE_PORT..."
tar czf - -C "$(dirname "$SOURCE_DIR")" "$(basename "$SOURCE_DIR")" 2>/dev/null | tee /tmp/backup_pipe | nc $REMOTE_HOST $REMOTE_PORT
# Aufräumen
kill $STATUS_PID 2>/dev/null
kill $MONITOR_PID 2>/dev/null
exec 3>&-
rm -f /tmp/backup_pipe
echo "Backup abgeschlossen."#!/bin/bash
# Zenralisierte Protokollsammlung von mehreren Servern
# Server-Modus: Protokolle sammeln
log_collector() {
local port=12345
local log_dir="/var/log/remote"
mkdir -p "$log_dir"
echo "Starte Protokollsammler auf Port $port..."
while true; do
# Format: HOSTNAME:LOGFILE:DATA
nc -l $port | while IFS=':' read -r hostname logfile data; do
# Zielverzeichnis für diesen Host
local host_dir="$log_dir/$hostname"
mkdir -p "$host_dir"
# Zum Log hinzufügen
echo "$(date '+%Y-%m-%d %H:%M:%S') $data" >> "$host_dir/$(basename "$logfile")"
echo "Protokolleintrag von $hostname für $(basename "$logfile") empfangen"
done
done
}
# Client-Modus: Protokolle senden
log_sender() {
local collector_host="$1"
local collector_port=12345
local log_file="$2"
hostname=$(hostname)
# Datei überwachen und neue Zeilen senden
tail -f "$log_file" | while read -r line; do
echo "$hostname:$log_file:$line" | nc -w 2 $collector_host $collector_port
done
}
# Verwendung basierend auf Parametern
case "$1" in
"collector")
log_collector
;;
"sender")
if [[ -z "$2" || -z "$3" ]]; then
echo "Verwendung: $0 sender <collector_host> <log_file>"
exit 1
fi
log_sender "$2" "$3"
;;
*)
echo "Verwendung: $0 {collector|sender <collector_host> <log_file>}"
exit 1
;;
esacObwohl netcat ein vielseitiges Werkzeug ist, gibt es einige Situationen, in denen Alternativen vorzuziehen sind:
# Einfacher TCP-Server mit socat
socat TCP-LISTEN:12345,fork STDOUT
# Bidirektionaler Datentransfer
socat TCP-LISTEN:12345,fork TCP:target.example.com:80
# Unix-Domain-Socket-Server
socat UNIX-LISTEN:/tmp/socket,fork STDOUT# SSL/TLS-verschlüsselter Server
ncat --ssl -l 12345
# Verbindung mit Client-Zertifikatsauthentifizierung
ncat --ssl --ssl-verify --ssl-cert cert.pem --ssl-key key.pem -l 12345
# Verbindungsbeschränkung auf bestimmte IPs
ncat -l 12345 --allow 192.168.1.0/24Sicherheitsüberlegungen: Begrenzen Sie die Exposition von netcat-Servern auf vertrauenswürdige Netzwerke.
Timeouts implementieren: Verwenden Sie immer angemessene Timeouts, um hängende Verbindungen zu vermeiden.
Verbindungsbegrenzung: Begrenzen Sie die Anzahl gleichzeitiger Verbindungen, um Ressourcenerschöpfung zu verhindern.
Protokollierung: Implementieren Sie Protokollierung für alle netcat-Operationen zur Fehlersuche und Prüfung.
Berechtigungen: Führen Sie netcat mit den geringsten erforderlichen Berechtigungen aus.
Alternative Tools: Erwägen Sie für Produktionsumgebungen spezialisiertere Tools wie socat oder ncat.
Escape-Zeichen beachten: Achten Sie auf korrekte Handhabung von Zeilenumbrüchen und Escape-Sequenzen.
Netcat ist ein leistungsstarkes und vielseitiges Werkzeug für Netzwerkoperationen und kann in Bash-Skripten effektiv für verschiedene Aufgaben eingesetzt werden, von einfachen Netzwerktests bis hin zu komplexeren Client-Server-Interaktionen. Mit angemessener Sorgfalt hinsichtlich Sicherheit und Fehlerbehandlung kann netcat ein wertvoller Bestandteil des Werkzeugkastens eines Systemadministrators oder Entwicklers sein.
Die Netzwerksicherheit ist ein wesentlicher Bestandteil jeder
Systemadministration. In Linux-Umgebungen wird die Paketfilterung
hauptsächlich durch den Kernel-Firewall-Mechanismus
netfilter implementiert, der über die Kommandozeilen-Tools
iptables (für IPv4) und ip6tables (für IPv6)
konfiguriert wird. In modernen Linux-Distributionen steht zusätzlich
nftables als Nachfolger zur Verfügung. In diesem Abschnitt
werden wir erkunden, wie Bash-Skripte zur automatisierten Konfiguration,
Überwachung und Verwaltung von Firewalls eingesetzt werden können.
iptables organisiert Filterregeln in Tabellen und
Ketten. Die wichtigsten Tabellen sind:
Jede Tabelle enthält vordefinierte Ketten:
# Regeln anzeigen
sudo iptables -L -v
# Regel hinzufügen (SSH erlauben)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Regel mit Quell-IP-Beschränkung
sudo iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# Regel löschen
sudo iptables -D INPUT -p tcp --dport 22 -j ACCEPT
# Regel am Anfang einer Kette einfügen
sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT
# Standardrichtlinie für eine Kette setzen
sudo iptables -P INPUT DROP#!/bin/bash
# Einfaches Firewall-Skript für einen Server
# Sicherstellen, dass das Skript als Root ausgeführt wird
if [[ $EUID -ne 0 ]]; then
echo "Dieses Skript muss als Root ausgeführt werden" >&2
exit 1
fi
# Bestehende Regeln löschen
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
# Standardrichtlinien setzen
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Loopback-Interface erlauben
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Bestehende Verbindungen erlauben
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# SSH-Zugriff erlauben
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# HTTP und HTTPS erlauben
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# ICMP (Ping) erlauben
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# DNS-Antworten erlauben
iptables -A INPUT -p udp --sport 53 -j ACCEPT
# Alle anderen eingehenden Pakete protokollieren und verwerfen
iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A INPUT -j DROP
echo "Firewall-Regeln wurden konfiguriert."#!/bin/bash
# Erweitertes Firewall-Skript mit Konfigurationsdatei
CONFIG_FILE="/etc/firewall/config"
BACKUP_DIR="/var/backups/firewall"
LOG_FILE="/var/log/firewall.log"
# Standardwerte
SSH_PORT=22
HTTP_ENABLED=1
HTTPS_ENABLED=1
ALLOWED_IPS=()
CUSTOM_RULES_FILE=""
RATE_LIMIT_SSH=1 # 1 für aktiviert, 0 für deaktiviert
MAX_SSH_CONNECTIONS=5
SSH_RATE_TIME=60 # Sekunden
# Logging-Funktion
log() {
local level="$1"
local message="$2"
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message" >> "$LOG_FILE"
echo "[$level] $message"
}
# Konfigurationsdatei laden, falls vorhanden
if [[ -f "$CONFIG_FILE" ]]; then
log "INFO" "Lade Konfiguration aus $CONFIG_FILE"
source "$CONFIG_FILE"
else
log "WARN" "Konfigurationsdatei $CONFIG_FILE nicht gefunden, verwende Standardwerte"
fi
# Verzeichnisse erstellen, falls sie nicht existieren
mkdir -p "$(dirname "$LOG_FILE")" "$BACKUP_DIR"
# Aktuelle Regeln sichern
iptables-save > "$BACKUP_DIR/iptables-$(date +%Y%m%d-%H%M%S).rules"
# Bestehende Regeln löschen
reset_firewall() {
log "INFO" "Lösche bestehende Firewall-Regeln"
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
# Standardrichtlinien setzen
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
}
# Grundlegende Regeln anwenden
apply_basic_rules() {
log "INFO" "Konfiguriere grundlegende Firewall-Regeln"
# Loopback-Interface erlauben
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Bestehende Verbindungen erlauben
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# ICMP (Ping) erlauben - mit Rate-Limiting
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT
# DNS-Antworten erlauben
iptables -A INPUT -p udp --sport 53 -j ACCEPT
}
# Dienste konfigurieren
configure_services() {
# SSH
log "INFO" "Konfiguriere SSH-Zugriff auf Port $SSH_PORT"
# SSH mit Rate-Limiting für Brute-Force-Schutz
if [[ "$RATE_LIMIT_SSH" -eq 1 ]]; then
log "INFO" "Aktiviere Rate-Limiting für SSH"
# Neue Kette für SSH-Verbindungen
iptables -N SSH_CHECK
# Begrenze neue Verbindungen
iptables -A SSH_CHECK -m conntrack --ctstate NEW -m recent --set
iptables -A SSH_CHECK -m conntrack --ctstate NEW -m recent --update --seconds $SSH_RATE_TIME --hitcount $MAX_SSH_CONNECTIONS -j DROP
# SSH-Verkehr an die SSH_CHECK-Kette weiterleiten
iptables -A INPUT -p tcp --dport $SSH_PORT -j SSH_CHECK
fi
# SSH-Zugriff erlauben
if [[ ${#ALLOWED_IPS[@]} -gt 0 ]]; then
# Nur von bestimmten IPs erlauben
for ip in "${ALLOWED_IPS[@]}"; do
iptables -A INPUT -p tcp --dport $SSH_PORT -s "$ip" -j ACCEPT
done
log "INFO" "SSH-Zugriff auf die IPs beschränkt: ${ALLOWED_IPS[*]}"
else
# Von überall erlauben
iptables -A INPUT -p tcp --dport $SSH_PORT -j ACCEPT
fi
# HTTP und HTTPS
[[ "$HTTP_ENABLED" -eq 1 ]] && {
log "INFO" "Erlaube HTTP-Verkehr"
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
}
[[ "$HTTPS_ENABLED" -eq 1 ]] && {
log "INFO" "Erlaube HTTPS-Verkehr"
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
}
}
# Benutzerdefinierte Regeln laden
load_custom_rules() {
if [[ -n "$CUSTOM_RULES_FILE" && -f "$CUSTOM_RULES_FILE" ]]; then
log "INFO" "Lade benutzerdefinierte Regeln aus $CUSTOM_RULES_FILE"
source "$CUSTOM_RULES_FILE"
fi
}
# Abschlussregeln
finalize_rules() {
log "INFO" "Konfiguriere Abschlussregeln"
# Protokollierung für verworfene Pakete
iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A INPUT -j DROP
log "INFO" "Firewall-Konfiguration abgeschlossen"
}
# Hauptfunktion
configure_firewall() {
log "INFO" "Starte Firewall-Konfiguration"
reset_firewall
apply_basic_rules
configure_services
load_custom_rules
finalize_rules
# Regeln speichern
if command -v iptables-save >/dev/null 2>&1; then
iptables-save > /etc/iptables/rules.v4
log "INFO" "Firewall-Regeln wurden in /etc/iptables/rules.v4 gespeichert"
fi
}
# Firewall-Status anzeigen
show_status() {
echo "Aktuelle Firewall-Regeln:"
echo "------------------------"
iptables -L -v
}
# Skriptausführung basierend auf Parametern
case "$1" in
start|restart)
configure_firewall
;;
stop)
log "INFO" "Deaktiviere Firewall"
reset_firewall
# Alles erlauben
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
;;
status)
show_status
;;
*)
echo "Verwendung: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit 0# /etc/firewall/config
# SSH-Konfiguration
SSH_PORT=2222
RATE_LIMIT_SSH=1
MAX_SSH_CONNECTIONS=3
SSH_RATE_TIME=60
# Webdienste
HTTP_ENABLED=1
HTTPS_ENABLED=1
# Zugriffsbeschränkungen
ALLOWED_IPS=("192.168.1.0/24" "10.0.0.5")
# Benutzerdefinierte Regeln
CUSTOM_RULES_FILE="/etc/firewall/custom_rules.sh"# /etc/firewall/custom_rules.sh
# FTP passiv erlauben
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
# Passive FTP-Ports
iptables -A INPUT -p tcp --dport 1024:1048 -j ACCEPT
# MySQL-Zugriff nur vom lokalen Netzwerk
iptables -A INPUT -p tcp --dport 3306 -s 192.168.1.0/24 -j ACCEPT
# OpenVPN
iptables -A INPUT -p udp --dport 1194 -j ACCEPTnftables ist der designierte Nachfolger von
iptables und bietet eine verbesserte Syntax und
Leistung:
#!/bin/bash
# Grundlegendes nftables-Firewall-Skript
# Sicherstellen, dass das Skript als Root ausgeführt wird
if [[ $EUID -ne 0 ]]; then
echo "Dieses Skript muss als Root ausgeführt werden" >&2
exit 1
fi
# Temporäre Datei für die Regeln
TEMP_FILE=$(mktemp)
# nftables-Regeln in die temporäre Datei schreiben
cat > "$TEMP_FILE" << 'EOF'
#!/usr/sbin/nft -f
# Bestehende Regeln löschen
flush ruleset
# Tabelle für IPv4-Filter definieren
table inet filter {
# Basis-Ketten definieren
chain input {
type filter hook input priority 0; policy drop;
# Loopback-Verkehr erlauben
iif lo accept
# Bestehende Verbindungen erlauben
ct state established,related accept
# ICMP und IGMP erlauben
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
# SSH erlauben
tcp dport 22 accept
# HTTP und HTTPS erlauben
tcp dport { 80, 443 } accept
# DNS-Antworten erlauben
udp sport 53 accept
# Alles andere protokollieren und verwerfen
log prefix "nftables-dropped: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
EOF
# Regeln anwenden
nft -f "$TEMP_FILE"
# Backup erstellen
cp "$TEMP_FILE" /etc/nftables.conf
# Temporäre Datei löschen
rm "$TEMP_FILE"
echo "nftables-Firewall wurde konfiguriert und in /etc/nftables.conf gespeichert."#!/bin/bash
# Firewall-Protokollanalyse-Skript
LOG_FILE="/var/log/kern.log"
FIREWALL_LOG="/var/log/firewall-analysis.log"
TEMP_FILE=$(mktemp)
# Firewall-Einträge extrahieren (für iptables)
grep "IPTables-Dropped" "$LOG_FILE" > "$TEMP_FILE"
# Statistiken erstellen
echo "=== Firewall-Protokollanalyse $(date) ===" > "$FIREWALL_LOG"
echo "" >> "$FIREWALL_LOG"
echo "Die 10 häufigsten Quell-IPs:" >> "$FIREWALL_LOG"
grep -oE "SRC=[0-9.]+" "$TEMP_FILE" | sort | uniq -c | sort -nr | head -10 >> "$FIREWALL_LOG"
echo "" >> "$FIREWALL_LOG"
echo "Die 10 häufigsten Zielports:" >> "$FIREWALL_LOG"
grep -oE "DPT=[0-9]+" "$TEMP_FILE" | sort | uniq -c | sort -nr | head -10 >> "$FIREWALL_LOG"
echo "" >> "$FIREWALL_LOG"
echo "Protokollverteilung:" >> "$FIREWALL_LOG"
grep -oE "PROTO=[A-Za-z0-9]+" "$TEMP_FILE" | sort | uniq -c | sort -nr >> "$FIREWALL_LOG"
echo "" >> "$FIREWALL_LOG"
echo "Zeitliche Verteilung (pro Stunde):" >> "$FIREWALL_LOG"
grep -oE "^[A-Za-z]{3}\ [0-9]+\ [0-9]{2}" "$TEMP_FILE" | sort | uniq -c >> "$FIREWALL_LOG"
# Für nftables
grep "nftables-dropped" "$LOG_FILE" >> "$TEMP_FILE"
# Entsprechende Analyseschritte für nftables-Format hinzufügen...
# Temporäre Datei löschen
rm "$TEMP_FILE"
echo "Firewall-Protokollanalyse wurde in $FIREWALL_LOG gespeichert."#!/bin/bash
# Automatisches Blockieren von potenziellen Angreifern
LOG_FILE="/var/log/kern.log"
BLOCK_TIME=3600 # Blockierungsdauer in Sekunden
MAX_ATTEMPTS=5 # Maximale Anzahl von Verbindungsversuchen
WHITELIST=("192.168.1.0/24" "10.0.0.5") # Nicht zu blockierende IPs
# Temporäre Datei für die IP-Liste
TEMP_FILE=$(mktemp)
# SSH-Brute-Force-Versuche erkennen
grep "Failed password" /var/log/auth.log | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | sort | uniq -c > "$TEMP_FILE"
# IP-Tabelle für blockierte Adressen erstellen (falls noch nicht vorhanden)
iptables -L BLOCKED 2>/dev/null || iptables -N BLOCKED
# Alte Regeln löschen (nach Ablauf der Blockierungszeit)
find /tmp/blocked_ips.* -type f -mmin +$((BLOCK_TIME / 60)) -exec rm {} \;
# INPUT-Kette aktualisieren, um BLOCKED zu verwenden (falls noch nicht vorhanden)
iptables -C INPUT -j BLOCKED 2>/dev/null || iptables -A INPUT -j BLOCKED
# Neue IPs blockieren
while read count ip; do
# Prüfen, ob die Anzahl der Versuche den Schwellenwert überschreitet
if [[ $count -ge $MAX_ATTEMPTS ]]; then
# Prüfen, ob die IP nicht auf der Whitelist steht
is_whitelisted=0
for white_ip in "${WHITELIST[@]}"; do
if [[ "$ip" == "$white_ip" || "$(ipcalc -n "$ip" "$white_ip" | grep -c 'NETWORK')" -eq 1 ]]; then
is_whitelisted=1
break
fi
done
# IP blockieren, wenn nicht auf der Whitelist
if [[ $is_whitelisted -eq 0 ]]; then
# Prüfen, ob die IP bereits blockiert ist
if ! iptables -C BLOCKED -s "$ip" -j DROP 2>/dev/null; then
echo "Blockiere IP $ip für $BLOCK_TIME Sekunden (Grund: $count fehlgeschlagene SSH-Anmeldeversuche)"
iptables -A BLOCKED -s "$ip" -j DROP
# Zeitstempel für späteres Entfernen speichern
touch "/tmp/blocked_ips.$ip"
fi
fi
fi
done < "$TEMP_FILE"
# Temporäre Datei löschen
rm "$TEMP_FILE"
# Alte Blockierungen entfernen
for block_file in /tmp/blocked_ips.*; do
[[ -f "$block_file" ]] || continue
# IP aus dem Dateinamen extrahieren
ip=$(basename "$block_file" | cut -d. -f2-)
# Prüfen, ob die Blockierungszeit abgelaufen ist
if [[ -f "$block_file" && $(find "$block_file" -mmin +$((BLOCK_TIME / 60)) | wc -l) -gt 0 ]]; then
echo "Entferne Blockierung für IP $ip (Zeitraum abgelaufen)"
iptables -D BLOCKED -s "$ip" -j DROP 2>/dev/null
rm "$block_file"
fi
donePort-Knocking ist eine Technik, bei der bestimmte Ports in einer definierten Reihenfolge angeklopft werden müssen, bevor ein normalerweise geschlossener Port (z.B. SSH) geöffnet wird:
#!/bin/bash
# Port-Knocking-Implementierung
# Konfiguration
KNOCK_SEQUENCE=(7000 8000 9000) # Ports, die in dieser Reihenfolge angeklopft werden müssen
OPEN_PORT=22 # Port, der nach erfolgreichem Klopfen geöffnet wird
ALLOW_TIME=30 # Zeit in Sekunden, für die der Port geöffnet bleibt
LOG_FILE="/var/log/knockd.log"
# Sicherstellen, dass das Skript als Root ausgeführt wird
if [[ $EUID -ne 0 ]]; then
echo "Dieses Skript muss als Root ausgeführt werden" >&2
exit 1
fi
# Protokollierungsfunktion
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
# Iptables-Ketten einrichten
setup_chains() {
# KNOCKSEQUENCE-Kette erstellen, falls noch nicht vorhanden
iptables -L KNOCKSEQUENCE &>/dev/null || iptables -N KNOCKSEQUENCE
# KNOCKAUTH-Kette erstellen, falls noch nicht vorhanden
iptables -L KNOCKAUTH &>/dev/null || iptables -N KNOCKAUTH
# Sicherstellen, dass der Zielport standardmäßig blockiert ist
iptables -C INPUT -p tcp --dport $OPEN_PORT -j KNOCKAUTH 2>/dev/null || \
iptables -A INPUT -p tcp --dport $OPEN_PORT -j KNOCKAUTH
# Klopfsequenz an KNOCKSEQUENCE weiterleiten
for port in "${KNOCK_SEQUENCE[@]}"; do
iptables -C INPUT -p tcp --dport $port -j KNOCKSEQUENCE 2>/dev/null || \
iptables -A INPUT -p tcp --dport $port -j KNOCKSEQUENCE
done
log "Knock-Ketten eingerichtet"
}
# tcpdump starten, um Port-Knocks zu überwachen
start_knock_monitor() {
# Sequenz als String für tcpdump-Filter
sequence_filter=""
for port in "${KNOCK_SEQUENCE[@]}"; do
[[ -n "$sequence_filter" ]] && sequence_filter="$sequence_filter or "
sequence_filter="${sequence_filter}tcp dst port $port"
done
log "Starte Knock-Monitor mit Filter: $sequence_filter"
# tcpdump im Hintergrund starten und Ausgabe verarbeiten
tcpdump -l -n "($sequence_filter)" 2>/dev/null | while read line; do
process_knock "$line"
done &
# PID speichern
echo $! > /var/run/knockd.pid
log "Knock-Monitor gestartet mit PID $(cat /var/run/knockd.pid)"
}
# Verarbeitung der Knock-Sequenz
process_knock() {
local packet="$1"
# IP-Adresse und Port aus dem Paket extrahieren
local ip=$(echo "$packet" | grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | head -1)
local port=$(echo "$packet" | grep -oE "\.([0-9]+) " | grep -oE "[0-9]+" | head -1)
[[ -z "$ip" || -z "$port" ]] && return
log "Knock von $ip auf Port $port"
# Status-Datei für diese IP
local status_file="/tmp/knock_${ip//\./_}"
# Neue Knock-Sequenz starten oder bestehende aktualisieren
if [[ ! -f "$status_file" ]]; then
# Prüfen, ob der erste Port in der Sequenz getroffen wurde
if [[ "$port" -eq "${KNOCK_SEQUENCE[0]}" ]]; then
echo "1" > "$status_file"
log "Neue Knock-Sequenz von $ip gestartet (1/${#KNOCK_SEQUENCE[@]})"
fi
else
# Aktuelle Position in der Sequenz
local current_pos=$(cat "$status_file")
# Prüfen, ob der nächste Port in der Sequenz getroffen wurde
if [[ "$port" -eq "${KNOCK_SEQUENCE[$current_pos]}" ]]; then
current_pos=$((current_pos + 1))
# Sequenz vollständig?
if [[ "$current_pos" -eq "${#KNOCK_SEQUENCE[@]}" ]]; then
log "Vollständige Knock-Sequenz von $ip empfangen - öffne Port $OPEN_PORT für $ALLOW_TIME Sekunden"
# Port für die IP öffnen
iptables -A KNOCKAUTH -s "$ip" -j ACCEPT
# Status-Datei löschen
rm "$status_file"
# Timer zum Schließen des Ports
{
sleep $ALLOW_TIME
log "Schließe Port $OPEN_PORT für $ip (Zeitraum abgelaufen)"
iptables -D KNOCKAUTH -s "$ip" -j ACCEPT
} &
else
# Nächste Position speichern
echo "$current_pos" > "$status_file"
log "Knock-Sequenz von $ip fortgesetzt ($current_pos/${#KNOCK_SEQUENCE[@]})"
fi
elif [[ "$port" -eq "${KNOCK_SEQUENCE[0]}" ]]; then
# Sequenz neu starten, wenn der erste Port erneut angeklopft wurde
echo "1" > "$status_file"
log "Knock-Sequenz von $ip zurückgesetzt (1/${#KNOCK_SEQUENCE[@]})"
else
# Ungültiger Knock, Sequenz zurücksetzen
rm "$status_file"
log "Ungültiger Knock von $ip auf Port $port - Sequenz zurückgesetzt"
fi
fi
}
# Hauptteil des Skripts
case "$1" in
start)
setup_chains
start_knock_monitor
;;
stop)
if [[ -f /var/run/knockd.pid ]]; then
kill $(cat /var/run/knockd.pid)
rm /var/run/knockd.pid
log "Knock-Monitor gestoppt"
else
echo "Knock-Daemon läuft nicht"
fi
;;
status)
if [[ -f /var/run/knockd.pid ]] && kill -0 $(cat /var/run/knockd.pid) 2>/dev/null; then
echo "Knock-Daemon läuft mit PID $(cat /var/run/knockd.pid)"
else
echo "Knock-Daemon läuft nicht"
fi
;;
*)
echo "Verwendung: $0 {start|stop|status}"
exit 1
;;
esac
exit 0#!/bin/bash
# Skript zur Erstellung eines systemd-Dienstes für die Firewall
# Pfad zum Firewall-Skript
FIREWALL_SCRIPT="/usr/local/sbin/firewall.sh"
# systemd-Service-Datei erstellen
cat > /etc/systemd/system/firewall.service << EOF
[Unit]
Description=Firewall-Regeln
After=network.target
[Service]
Type=oneshot
ExecStart=$FIREWALL_SCRIPT start
ExecStop=$FIREWALL_SCRIPT stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# systemd informieren
systemctl daemon-reload
# Dienst aktivieren und starten
systemctl enable firewall.service
systemctl start firewall.service
echo "Firewall-Dienst wurde erstellt und aktiviert."Sicherungsregeln einrichten: Stellen Sie sicher, dass Ihre Skripte eine sichere Fallback-Konfiguration haben, falls etwas schief geht.
Testen vor Anwendung: Testen Sie Ihre Firewall-Skripte in einer Entwicklungsumgebung, bevor Sie sie in der Produktion einsetzen.
Rollback-Mechanismus: Implementieren Sie einen Rollback-Mechanismus, der die vorherigen Regeln wiederherstellen kann, wenn die neuen Regeln Probleme verursachen.
Dokumentation: Dokumentieren Sie jede Regel, insbesondere in komplexen Firewall-Konfigurationen.
Modulare Struktur: Organisieren Sie Ihre Firewall-Skripte in modulare Komponenten für bessere Wartbarkeit.
Regelmäßige Überprüfung: Überprüfen Sie regelmäßig Ihre Firewall-Regeln auf Redundanzen oder Sicherheitslücken.
Protokollierung und Überwachung: Implementieren Sie angemessene Protokollierung und Überwachung, um potenzielle Angriffe zu erkennen.
Fokus auf Standardprotokolle: Vermeiden Sie, sich auf nicht-standardisierte oder herstellerspezifische Funktionen zu verlassen.
IPv6-Unterstützung: Vergessen Sie nicht, Ihre Firewall-Regeln auch für IPv6 zu konfigurieren.
Prinzip der geringsten Privilegien: Erlauben Sie nur den Verkehr, der für den Betrieb notwendig ist.
Automatisierte Verifizierung: Implementieren Sie Tests, die nach Regeländerungen die Funktionsfähigkeit kritischer Dienste überprüfen.
Versionskontrolle: Führen Sie eine Versionskontrolle für Ihre Firewall-Skripte, um Änderungen nachverfolgen zu können.
Redundanz vermeiden: Vermeiden Sie redundante Regeln, die die Leistung beeinträchtigen könnten.
Regeln optimieren: Platzieren Sie häufig verwendete Regeln am Anfang der Kette, um die Verarbeitungsgeschwindigkeit zu erhöhen.
Fehlerbehandlung: Implementieren Sie robuste Fehlerbehandlung in Ihren Skripten.
State-Tracking begrenzen: Begrenzen Sie die Anzahl der gleichzeitigen Verbindungen im State-Tracking-System, um DoS-Angriffe zu verhindern.
Outbound-Filterung: Filtern Sie nicht nur eingehenden, sondern auch ausgehenden Verkehr.
Regelmäßige Aktualisierung: Aktualisieren Sie Ihre Firewall-Regeln entsprechend neuen Bedrohungen und Anforderungen.
Umgebungsspezifische Regeln: Passen Sie Ihre Firewall-Regeln an die spezifische Umgebung an (Entwicklung, Test, Produktion).
Notfallzugriff: Implementieren Sie Mechanismen für den Notfallzugriff, falls reguläre Zugriffskanäle blockiert sind.
Die effektive Überwachung und Diagnose von Netzwerken ist ein wesentlicher Bestandteil der Systemadministration. Mit Bash-Skripten können Administratoren leistungsfähige, maßgeschneiderte Monitoring-Lösungen erstellen, die kontinuierlich die Netzwerkgesundheit überwachen und bei Problemen frühzeitig alarmieren. In diesem Abschnitt werden wir verschiedene Techniken und Tools für das Netzwerkmonitoring und die Diagnose mit Bash erkunden.
#!/bin/bash
# Einfaches Host-Monitoring mit Ping
HOSTS=("192.168.1.1" "server1.example.com" "10.0.0.5")
LOG_FILE="/var/log/ping_monitor.log"
TIMEOUT=2 # Timeout in Sekunden
MAX_RETRIES=3
# Sicherstellen, dass das Log-Verzeichnis existiert
mkdir -p "$(dirname "$LOG_FILE")"
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
check_host() {
local host="$1"
local retries=0
while [[ $retries -lt $MAX_RETRIES ]]; do
if ping -c 1 -W $TIMEOUT "$host" &>/dev/null; then
echo "$host ist erreichbar"
log "$host ist erreichbar (Latenz: $(ping -c 1 -W $TIMEOUT "$host" | grep "time=" | cut -d= -f4) ms)"
return 0
fi
((retries++))
sleep 1
done
echo "$host ist NICHT erreichbar nach $MAX_RETRIES Versuchen!" >&2
log "$host ist NICHT erreichbar nach $MAX_RETRIES Versuchen!"
return 1
}
log "=== Start der Ping-Überwachung ==="
for host in "${HOSTS[@]}"; do
check_host "$host"
done
log "=== Ende der Ping-Überwachung ==="#!/bin/bash
# Kontinuierliche Netzwerküberwachung mit E-Mail-Benachrichtigung
HOSTS_FILE="/etc/network-monitor/hosts.txt"
LOG_FILE="/var/log/network_monitor.log"
STATUS_FILE="/tmp/network_status.txt"
CHECK_INTERVAL=300 # Prüfintervall in Sekunden
ALERT_EMAIL="admin@example.com"
MAIL_PROGRAM="mail" # Alternative: "mailx" oder "sendmail"
# Status-Codes
UP=0
DOWN=1
RECOVERED=2
# Prüfen, ob die benötigten Dateien existieren
[[ -f "$HOSTS_FILE" ]] || { echo "Fehler: Hosts-Datei $HOSTS_FILE nicht gefunden"; exit 1; }
mkdir -p "$(dirname "$LOG_FILE")"
touch "$STATUS_FILE" 2>/dev/null || { echo "Fehler: Kann Status-Datei nicht erstellen"; exit 1; }
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
echo "$1"
}
send_alert() {
local subject="$1"
local message="$2"
log "Sende Benachrichtigung: $subject"
echo -e "$message" | $MAIL_PROGRAM -s "$subject" "$ALERT_EMAIL"
}
check_host() {
local host="$1"
local hostname="${host%%,*}" # Format: "hostname,description"
local description="${host#*,}"
# Wenn kein Beschreibungstext vorhanden ist, verwende den Hostnamen
[[ "$hostname" == "$description" ]] && description="$hostname"
# Status des Hosts aus der Status-Datei lesen
local previous_status=""
if grep -q "^$hostname:" "$STATUS_FILE"; then
previous_status=$(grep "^$hostname:" "$STATUS_FILE" | cut -d: -f2)
else
previous_status="UNKNOWN"
fi
# Host prüfen
if ping -c 3 -W 2 "$hostname" &>/dev/null; then
if [[ "$previous_status" == "DOWN" ]]; then
# Host war vorher nicht erreichbar, jetzt aber wieder
log "$description ($hostname) ist wieder erreichbar"
send_alert "Server $description ist wieder ONLINE" \
"Der Server $description ($hostname) ist nach dem Ausfall wieder erreichbar.\n\nZeitstempel: $(date)"
# Status aktualisieren
sed -i "/^$hostname:/d" "$STATUS_FILE"
echo "$hostname:UP" >> "$STATUS_FILE"
return $RECOVERED
elif [[ "$previous_status" != "UP" ]]; then
# Host ist neu oder war unbekannt
log "$description ($hostname) ist erreichbar"
# Status aktualisieren
sed -i "/^$hostname:/d" "$STATUS_FILE"
echo "$hostname:UP" >> "$STATUS_FILE"
return $UP
else
# Host war vorher erreichbar und ist es immer noch
return $UP
fi
else
if [[ "$previous_status" != "DOWN" ]]; then
# Host war vorher erreichbar oder unbekannt, jetzt aber nicht mehr
log "$description ($hostname) ist NICHT erreichbar!"
send_alert "KRITISCH: Server $description ist OFFLINE" \
"Der Server $description ($hostname) ist nicht erreichbar.\n\nZeitstempel: $(date)"
# Status aktualisieren
sed -i "/^$hostname:/d" "$STATUS_FILE"
echo "$hostname:DOWN" >> "$STATUS_FILE"
fi
return $DOWN
fi
}
# Endlosschleife für kontinuierliche Überwachung
log "=== Netzwerküberwachung gestartet ==="
while true; do
log "Starte Prüfdurchlauf..."
# Status-Zusammenfassung
up_count=0
down_count=0
# Alle Hosts prüfen
while IFS= read -r host || [[ -n "$host" ]]; do
# Kommentare und leere Zeilen überspringen
[[ -z "$host" || "$host" =~ ^# ]] && continue
check_host "$host"
status=$?
if [[ $status -eq $DOWN ]]; then
((down_count++))
else
((up_count++))
fi
done < "$HOSTS_FILE"
log "Prüfdurchlauf abgeschlossen. $up_count Hosts erreichbar, $down_count Hosts nicht erreichbar."
# Warten bis zum nächsten Prüfzyklus
sleep $CHECK_INTERVAL
done#!/bin/bash
# Adaptive Netzwerküberwachung mit dynamischem Prüfintervall
HOSTS_FILE="/etc/network-monitor/hosts.txt"
LOG_FILE="/var/log/adaptive_monitor.log"
MIN_INTERVAL=60 # Minimales Intervall in Sekunden
MAX_INTERVAL=900 # Maximales Intervall in Sekunden
CURRENT_INTERVAL=$MIN_INTERVAL
FAILURES_THRESHOLD=3 # Schwellenwert für konsekutive Fehler
# Status-Tracking
declare -A host_failures
declare -A host_last_check
# Logging-Funktion
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Anpassen des Prüfintervalls basierend auf Netzwerkstatus
adjust_interval() {
local total_hosts=0
local down_hosts=0
for host in "${!host_failures[@]}"; do
((total_hosts++))
[[ ${host_failures[$host]} -ge $FAILURES_THRESHOLD ]] && ((down_hosts++))
done
# Wenn mehr als 20% der Hosts nicht erreichbar sind, verringere das Intervall
local down_percentage=$((down_hosts * 100 / total_hosts))
if [[ $down_percentage -gt 20 ]]; then
# Verringere das Intervall, aber nicht unter das Minimum
CURRENT_INTERVAL=$((CURRENT_INTERVAL / 2))
[[ $CURRENT_INTERVAL -lt $MIN_INTERVAL ]] && CURRENT_INTERVAL=$MIN_INTERVAL
log "Netzwerkprobleme erkannt ($down_percentage% Hosts nicht erreichbar). Intervall auf $CURRENT_INTERVAL Sekunden verringert."
elif [[ $down_percentage -eq 0 && $CURRENT_INTERVAL -lt $MAX_INTERVAL ]]; then
# Wenn alle Hosts erreichbar sind, erhöhe das Intervall schrittweise
CURRENT_INTERVAL=$((CURRENT_INTERVAL * 5 / 4))
[[ $CURRENT_INTERVAL -gt $MAX_INTERVAL ]] && CURRENT_INTERVAL=$MAX_INTERVAL
log "Netzwerk stabil. Intervall auf $CURRENT_INTERVAL Sekunden erhöht."
fi
}
# Host-Prüfung mit adaptivem Timeout
check_host() {
local host="$1"
local adaptive_timeout
# Letzten Check-Zeitpunkt aktualisieren
host_last_check[$host]=$(date +%s)
# Adaptiver Timeout basierend auf bisherigen Fehlerrate
if [[ ${host_failures[$host]:-0} -gt $FAILURES_THRESHOLD ]]; then
adaptive_timeout=5 # Längerer Timeout für problematische Hosts
else
adaptive_timeout=2 # Standardtimeout
fi
# Host prüfen
if ping -c 2 -W $adaptive_timeout "$host" &>/dev/null; then
if [[ ${host_failures[$host]:-0} -ge $FAILURES_THRESHOLD ]]; then
log "$host ist wieder erreichbar nach ${host_failures[$host]} fehlgeschlagenen Versuchen."
fi
host_failures[$host]=0
return 0
else
# Fehler inkrementieren
host_failures[$host]=$((${host_failures[$host]:-0} + 1))
# Bei Überschreitung des Schwellenwerts alarmieren
if [[ ${host_failures[$host]} -eq $FAILURES_THRESHOLD ]]; then
log "WARNUNG: $host ist seit $FAILURES_THRESHOLD Prüfungen nicht erreichbar!"
# Hier könnte eine Benachrichtigung erfolgen
fi
return 1
fi
}
# Hauptprogramm
log "=== Adaptive Netzwerküberwachung gestartet ==="
# Initialisierung
while IFS= read -r host || [[ -n "$host" ]]; do
# Kommentare und leere Zeilen überspringen
[[ -z "$host" || "$host" =~ ^# ]] && continue
host_failures[$host]=0
host_last_check[$host]=0
done < "$HOSTS_FILE"
# Endlosschleife
while true; do
log "Prüfdurchlauf mit Intervall $CURRENT_INTERVAL Sekunden..."
current_time=$(date +%s)
while IFS= read -r host || [[ -n "$host" ]]; do
# Kommentare und leere Zeilen überspringen
[[ -z "$host" || "$host" =~ ^# ]] && continue
# Prüfen, ob eine Prüfung fällig ist (basierend auf letztem Check)
time_since_last_check=$((current_time - ${host_last_check[$host]:-0}))
# Häufigere Prüfung für problematische Hosts
check_interval=$CURRENT_INTERVAL
[[ ${host_failures[$host]:-0} -ge $FAILURES_THRESHOLD ]] && check_interval=$((CURRENT_INTERVAL / 2))
if [[ $time_since_last_check -ge $check_interval ]]; then
log "Prüfe Host $host..."
check_host "$host"
fi
done < "$HOSTS_FILE"
# Intervall anpassen
adjust_interval
# Warten bis zum nächsten Zyklus
sleep $CURRENT_INTERVAL
done#!/bin/bash
# Umfassende Netzwerkdiagnose für einen Host
HOST="$1"
PORT="${2:-80}" # Standardport 80, falls nicht angegeben
TIMEOUT=5
OUTPUT_FILE="/tmp/network_diagnosis_$(date +%Y%m%d_%H%M%S).txt"
# Prüfen, ob ein Host angegeben wurde
if [[ -z "$HOST" ]]; then
echo "Verwendung: $0 <Hostname/IP> [Port]"
exit 1
fi
# Hilfsfunktion zur Befehlsausführung mit Ausgabeerfassung
run_command() {
local cmd_desc="$1"
local cmd="$2"
echo -e "\n=== $cmd_desc ===\n" >> "$OUTPUT_FILE"
echo "Führe aus: $cmd" >> "$OUTPUT_FILE"
# Befehl ausführen und Ausgabe erfassen
local output
output=$($cmd 2>&1)
local status=$?
echo -e "$output" >> "$OUTPUT_FILE"
echo -e "\nStatus: $status\n" >> "$OUTPUT_FILE"
# Für die Konsolenausgabe
echo "- $cmd_desc: "
if [[ $status -eq 0 ]]; then
echo " Erfolgreich"
else
echo " Fehlgeschlagen (Status $status)"
fi
}
echo "Starte umfassende Netzwerkdiagnose für $HOST:$PORT"
echo "Die vollständige Ausgabe wird in $OUTPUT_FILE gespeichert"
# Basisdaten zum Host erfassen
echo "=== Netzwerkdiagnose für $HOST:$PORT ===" > "$OUTPUT_FILE"
echo "Datum: $(date)" >> "$OUTPUT_FILE"
echo "Ausgeführt von: $(whoami)@$(hostname)" >> "$OUTPUT_FILE"
# DNS-Auflösung prüfen
run_command "DNS-Auflösung" "host $HOST"
# IP-Adresse bestimmen
ip_address=$(host "$HOST" 2>/dev/null | grep "has address" | head -1 | awk '{print $4}')
if [[ -z "$ip_address" ]]; then
# Versuchen, $HOST direkt als IP zu verwenden
if [[ "$HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
ip_address="$HOST"
else
echo "Konnte IP-Adresse für $HOST nicht ermitteln" | tee -a "$OUTPUT_FILE"
fi
fi
if [[ -n "$ip_address" ]]; then
# Routenverfolgung
run_command "Routenverfolgung" "traceroute -w 2 -m 15 $ip_address"
# Ping-Test
run_command "Ping-Test (5 Pakete)" "ping -c 5 -W 2 $ip_address"
# MTU-Ermittlung
run_command "MTU-Ermittlung" "ping -c 3 -M do -s 1472 $ip_address"
fi
# Port-Erreichbarkeit testen
run_command "Port-Test mit Netcat" "nc -zv -w $TIMEOUT $HOST $PORT"
# HTTPS-spezifische Tests, wenn Port 443
if [[ "$PORT" -eq 443 ]]; then
run_command "SSL-Zertifikatsinformationen" "openssl s_client -connect $HOST:$PORT -servername $HOST </dev/null 2>/dev/null | openssl x509 -text -noout"
fi
# Whois-Informationen (für Domains oder öffentliche IPs)
run_command "WHOIS-Informationen" "whois $HOST"
# Netzwerkschnittstellen und Routing-Informationen
run_command "Lokale Netzwerkschnittstellen" "ip addr show"
run_command "Routing-Tabelle" "ip route show"
# Zusammenfassung erstellen
echo -e "\n=== Zusammenfassung der Diagnose ===\n" >> "$OUTPUT_FILE"
# DNS-Status
if grep -q "has address" "$OUTPUT_FILE"; then
echo "DNS-Auflösung: Erfolgreich" >> "$OUTPUT_FILE"
else
echo "DNS-Auflösung: Fehlgeschlagen" >> "$OUTPUT_FILE"
fi
# Ping-Status
if grep -q "0% packet loss" "$OUTPUT_FILE"; then
echo "Ping: Erfolgreich (0% Paketverlust)" >> "$OUTPUT_FILE"
elif grep -q "packet loss" "$OUTPUT_FILE"; then
packet_loss=$(grep "packet loss" "$OUTPUT_FILE" | sed -E 's/.*([0-9]+)% packet loss.*/\1/')
echo "Ping: Teilweise erfolgreich ($packet_loss% Paketverlust)" >> "$OUTPUT_FILE"
else
echo "Ping: Fehlgeschlagen" >> "$OUTPUT_FILE"
fi
# Port-Status
if grep -q "succeeded" "$OUTPUT_FILE"; then
echo "Port $PORT: Offen" >> "$OUTPUT_FILE"
else
echo "Port $PORT: Geschlossen oder blockiert" >> "$OUTPUT_FILE"
fi
echo "Diagnose abgeschlossen. Ergebnisse wurden in $OUTPUT_FILE gespeichert."#!/bin/bash
# Netzwerkleistungsanalyse-Skript
TARGET="$1"
DURATION="${2:-60}" # Standarddauer: 60 Sekunden
OUTPUT_DIR="/var/log/network_performance"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
RESULT_FILE="$OUTPUT_DIR/perf_$TARGET_$TIMESTAMP.log"
# Benötigte Tools prüfen
for tool in ping iperf traceroute; do
if ! command -v $tool &>/dev/null; then
echo "Fehler: $tool ist nicht installiert" >&2
exit 1
fi
done
# Ausgabeverzeichnis erstellen
mkdir -p "$OUTPUT_DIR"
# Einleitung
echo "=== Netzwerkleistungsanalyse für $TARGET ===" | tee "$RESULT_FILE"
echo "Zeitstempel: $(date)" | tee -a "$RESULT_FILE"
echo "Dauer: $DURATION Sekunden" | tee -a "$RESULT_FILE"
echo "" | tee -a "$RESULT_FILE"
# Ping-Test für Latenz und Jitter
echo "Führe Ping-Test durch ($DURATION Sekunden)..." | tee -a "$RESULT_FILE"
ping_output=$(ping -c $DURATION -i 1 $TARGET 2>&1)
echo "$ping_output" >> "$RESULT_FILE"
# Latenz extrahieren
avg_latency=$(echo "$ping_output" | grep "avg" | sed -E 's/.*= [0-9.]+\/([0-9.]+)\/[0-9.]+\/.*/\1/')
min_latency=$(echo "$ping_output" | grep "avg" | sed -E 's/.*= ([0-9.]+)\/[0-9.]+\/[0-9.]+\/.*/\1/')
max_latency=$(echo "$ping_output" | grep "avg" | sed -E 's/.*= [0-9.]+\/[0-9.]+\/([0-9.]+)\/.*/\1/')
packet_loss=$(echo "$ping_output" | grep -o "[0-9.]*% packet loss" | cut -d" " -f1)
# Jitter berechnen (Standardabweichung der Latenz)
jitter=$(echo "$ping_output" | grep -oE "time=[0-9.]+ ms" | cut -d= -f2 | cut -d" " -f1 | awk '{sum+=$1; sumsq+=$1*$1} END {print sqrt(sumsq/NR - (sum/NR)^2)}')
echo -e "\nLatenz-Zusammenfassung:" | tee -a "$RESULT_FILE"
echo " Minimum: $min_latency ms" | tee -a "$RESULT_FILE"
echo " Durchschnitt: $avg_latency ms" | tee -a "$RESULT_FILE"
echo " Maximum: $max_latency ms" | tee -a "$RESULT_FILE"
echo " Jitter: $jitter ms" | tee -a "$RESULT_FILE"
echo " Paketverlust: $packet_loss" | tee -a "$RESULT_FILE"
# Bandbreitentest mit iperf, falls verfügbar
if [[ "$TARGET" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ || "$TARGET" =~ ^[a-zA-Z0-9][-a-zA-Z0-9]*(\.[a-zA-Z0-9][-a-zA-Z0-9]*)+$ ]]; then
echo -e "\nFühre Bandbreitentest mit iperf durch (falls iperf-Server auf $TARGET verfügbar)..." | tee -a "$RESULT_FILE"
iperf_output=$(iperf -c $TARGET -t 10 -i 1 2>&1 || echo "iperf-Server nicht verfügbar auf $TARGET")
echo "$iperf_output" >> "$RESULT_FILE"
if ! echo "$iperf_output" | grep -q "nicht verfügbar"; then
bandwidth=$(echo "$iperf_output" | tail -n 1 | awk '{print $7 " " $8}')
echo " Durchschnittliche Bandbreite: $bandwidth" | tee -a "$RESULT_FILE"
else
echo " Bandbreitentest nicht möglich (kein iperf-Server auf $TARGET)" | tee -a "$RESULT_FILE"
fi
fi
# Routenverfolgung
echo -e "\nFühre Routenverfolgung durch..." | tee -a "$RESULT_FILE"
traceroute_output=$(traceroute -w 2 -m 20 $TARGET 2>&1)
echo "$traceroute_output" >> "$RESULT_FILE"
# Hop-Anzahl extrahieren
hop_count=$(echo "$traceroute_output" | grep -c "^ [0-9]")
echo " Anzahl der Hops: $hop_count" | tee -a "$RESULT_FILE"
# MTU-Ermittlung durch Ping mit DF-Flag
echo -e "\nErmittle maximale MTU..." | tee -a "$RESULT_FILE"
for size in 1500 1472 1464 1400 1300 1200 1100 1000 900 800; do
ping_mtu=$(ping -c 2 -M do -s $size $TARGET 2>&1)
if echo "$ping_mtu" | grep -q "0% packet loss"; then
echo " Maximale MTU ist mindestens: $((size + 28)) Bytes" | tee -a "$RESULT_FILE"
break
fi
done
# Gesamtbewertung der Netzwerkleistung
echo -e "\n=== Gesamtbewertung der Netzwerkleistung ===" | tee -a "$RESULT_FILE"
# Latenz-Bewertung
if [[ $(echo "$avg_latency < 20" | bc -l) -eq 1 ]]; then
latency_rating="Ausgezeichnet"
elif [[ $(echo "$avg_latency < 50" | bc -l) -eq 1 ]]; then
latency_rating="Sehr gut"
elif [[ $(echo "$avg_latency < 100" | bc -l) -eq 1 ]]; then
latency_rating="Gut"
elif [[ $(echo "$avg_latency < 200" | bc -l) -eq 1 ]]; then
latency_rating="Mittel"
else
latency_rating="Schlecht"
fi
# Paketverlust-Bewertung
if [[ $(echo "$packet_loss < 0.1" | bc -l) -eq 1 ]]; then
loss_rating="Ausgezeichnet"
elif [[ $(echo "$packet_loss < 1.0" | bc -l) -eq 1 ]]; then
loss_rating="Sehr gut"
elif [[ $(echo "$packet_loss < 3.0" | bc -l) -eq 1 ]]; then
loss_rating="Gut"
elif [[ $(echo "$packet_loss < 10.0" | bc -l) -eq 1 ]]; then
loss_rating="Mittel"
else
loss_rating="Schlecht"
fi
# Jitter-Bewertung
if [[ $(echo "$jitter < 2" | bc -l) -eq 1 ]]; then
jitter_rating="Ausgezeichnet"
elif [[ $(echo "$jitter < 5" | bc -l) -eq 1 ]]; then
jitter_rating="Sehr gut"
elif [[ $(echo "$jitter < 10" | bc -l) -eq 1 ]]; then
jitter_rating="Gut"
elif [[ $(echo "$jitter < 20" | bc -l) -eq 1 ]]; then
jitter_rating="Mittel"
else
jitter_rating="Schlecht"
fi
echo "Latenz: $latency_rating ($avg_latency ms)" | tee -a "$RESULT_FILE"
echo "Jitter: $jitter_rating ($jitter ms)" | tee -a "$RESULT_FILE"
echo "Paketverlust: $loss_rating ($packet_loss)" | tee -a "$RESULT_FILE"
echo -e "\nLeistungsanalyse abgeschlossen. Vollständiger Bericht: $RESULT_FILE"#!/bin/bash
# Einfacher Netzwerkverkehrsmonitor
INTERFACE="$1"
INTERVAL="${2:-5}" # Standardintervall: 5 Sekunden
DURATION="${3:-60}" # Standarddauer: 60 Sekunden (0 für unbegrenzt)
LOG_FILE="/var/log/traffic_monitor.log"
# Prüfen, ob ein Netzwerkinterface angegeben wurde
if [[ -z "$INTERFACE" ]]; then
echo "Verwendung: $0 <Interface> [Intervall in Sekunden] [Dauer in Sekunden]"
echo "Verfügbare Interfaces:"
ip -br link show | awk '{print " " $1}'
exit 1
fi
# Prüfen, ob das Interface existiert
if ! ip link show dev "$INTERFACE" &>/dev/null; then
echo "Fehler: Interface $INTERFACE existiert nicht" >&2
exit 1
fi
# Hilfsfunktion zur Umrechnung von Bytes in lesbare Größen
format_bytes() {
local bytes="$1"
local units=("B" "KB" "MB" "GB" "TB")
local unit=0
while [[ $bytes -gt 1024 && $unit -lt 4 ]]; do
bytes=$(echo "scale=2; $bytes / 1024" | bc)
((unit++))
done
echo "$bytes ${units[$unit]}"
}
# Hilfsfunktion zur Berechnung der Übertragungsrate
calculate_rate() {
local current="$1"
local previous="$2"
local interval="$3"
local rate=$(echo "scale=2; ($current - $previous) / $interval" | bc)
echo "$rate"
}
echo "Starte Netzwerkverkehrsmonitor für Interface $INTERFACE"
echo "Intervall: $INTERVAL Sekunden"
if [[ $DURATION -gt 0 ]]; then
echo "Dauer: $DURATION Sekunden"
else
echo "Dauer: Unbegrenzt (STRG+C zum Beenden)"
fi
echo "Zeitstempel,Interface,RX_Bytes,TX_Bytes,RX_Rate,TX_Rate" > "$LOG_FILE"
# Initialisierung
start_time=$(date +%s)
previous_rx=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
previous_tx=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
previous_time=$start_time
# Statistik-Anzeige
printf "%-20s %-15s %-15s %-15s %-15s\n" "Zeitstempel" "RX_Rate" "TX_Rate" "RX_Total" "TX_Total"
printf "%s\n" "-----------------------------------------------------------------------"
# Hauptschleife
while true; do
current_time=$(date +%s)
elapsed=$((current_time - start_time))
# Prüfen, ob die Dauer überschritten wurde
if [[ $DURATION -gt 0 && $elapsed -ge $DURATION ]]; then
break
fi
# Aktuellen Verkehr lesen
current_rx=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
current_tx=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
# Berechnung der Raten
time_diff=$((current_time - previous_time))
rx_rate=$(calculate_rate "$current_rx" "$previous_rx" "$time_diff")
tx_rate=$(calculate_rate "$current_tx" "$previous_tx" "$time_diff")
# Formatierte Werte
rx_rate_formatted=$(format_bytes "$rx_rate")
tx_rate_formatted=$(format_bytes "$tx_rate")
total_rx_formatted=$(format_bytes "$current_rx")
total_tx_formatted=$(format_bytes "$current_tx")
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
# Bildschirmausgabe
printf "%-20s %-15s %-15s %-15s %-15s\n" \
"$timestamp" \
"${rx_rate_formatted}/s" \
"${tx_rate_formatted}/s" \
"$total_rx_formatted" \
"$total_tx_formatted"
# In Datei protokollieren
echo "$timestamp,$INTERFACE,$current_rx,$current_tx,$rx_rate,$tx_rate" >> "$LOG_FILE"
# Werte für nächste Iteration speichern
previous_rx=$current_rx
previous_tx=$current_tx
previous_time=$current_time
# Warten bis zum nächsten Intervall
sleep $INTERVAL
done
echo "Netzwerkmonitor beendet. Protokoll gespeichert in $LOG_FILE"#!/bin/bash
# Netzwerkverkehrsanalyse mit tcpdump
INTERFACE="$1"
DURATION="${2:-60}" # Standarddauer: 60 Sekunden
OUTPUT_DIR="/var/log/network_captures"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CAPTURE_FILE="$OUTPUT_DIR/capture_${INTERFACE}_${TIMESTAMP}.pcap"
SUMMARY_FILE="$OUTPUT_DIR/summary_${INTERFACE}_${TIMESTAMP}.txt"
# Prüfen, ob ein Netzwerkinterface angegeben wurde
if [[ -z "$INTERFACE" ]]; then
echo "Verwendung: $0 <Interface> [Dauer in Sekunden]"
echo "Verfügbare Interfaces:"
ip -br link show | awk '{print " " $1}'
exit 1
fi
# Prüfen, ob das Interface existiert
if ! ip link show dev "$INTERFACE" &>/dev/null; then
echo "Fehler: Interface $INTERFACE existiert nicht" >&2
exit 1
fi
# Prüfen, ob tcpdump installiert ist
if ! command -v tcpdump &>/dev/null; then
echo "Fehler: tcpdump ist nicht installiert" >&2
exit 1
fi
# Ausgabeverzeichnis erstellen
mkdir -p "$OUTPUT_DIR"
echo "Starte Netzwerkverkehrsanalyse für Interface $INTERFACE"
echo "Dauer: $DURATION Sekunden"
echo "Erfasse Verkehr in $CAPTURE_FILE..."
# Verkehr erfassen
tcpdump -i "$INTERFACE" -w "$CAPTURE_FILE" -G "$DURATION" -W 1 &
TCPDUMP_PID=$!
# Fortschrittsanzeige
total_seconds=$DURATION
for ((i=1; i<=total_seconds; i++)); do
percent=$((i * 100 / total_seconds))
completed=$((percent / 2))
remaining=$((50 - completed))
progress="["
for ((j=0; j<completed; j++)); do progress+="#"; done
for ((j=0; j<remaining; j++)); do progress+="-"; done
progress+="] $percent%"
echo -ne "$progress\r"
sleep 1
done
echo
# Warten, bis tcpdump beendet ist
wait $TCPDUMP_PID
echo "Verkehrserfassung abgeschlossen"
echo "Analysiere erfassten Verkehr..."
# Statistiken erstellen
echo "=== Netzwerkverkehrsanalyse für $INTERFACE ===" > "$SUMMARY_FILE"
echo "Zeitstempel: $(date)" >> "$SUMMARY_FILE"
echo "Erfassungsdauer: $DURATION Sekunden" >> "$SUMMARY_FILE"
echo "" >> "$SUMMARY_FILE"
# Protokollverteilung
echo "=== Protokollverteilung ===" >> "$SUMMARY_FILE"
tcpdump -r "$CAPTURE_FILE" -nn -q | awk '{print $2}' | cut -d: -f1 | sort | uniq -c | sort -nr >> "$SUMMARY_FILE"
# Top-Quell-IPs
echo "" >> "$SUMMARY_FILE"
echo "=== Top 10 Quell-IPs ===" >> "$SUMMARY_FILE"
tcpdump -r "$CAPTURE_FILE" -nn 'ip' | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -nr | head -10 >> "$SUMMARY_FILE"
# Top-Ziel-IPs
echo "" >> "$SUMMARY_FILE"
echo "=== Top 10 Ziel-IPs ===" >> "$SUMMARY_FILE"
tcpdump -r "$CAPTURE_FILE" -nn 'ip' | awk '{print $5}' | cut -d. -f1-4 | cut -d: -f1 | sort | uniq -c | sort -nr | head -10 >> "$SUMMARY_FILE"
# TCP-Ports
echo "" >> "$SUMMARY_FILE"
echo "=== Top 10 TCP-Ports ===" >> "$SUMMARY_FILE"
tcpdump -r "$CAPTURE_FILE" -nn 'tcp' | awk '{print $5}' | cut -d. -f5 | sort | uniq -c | sort -nr | head -10 >> "$SUMMARY_FILE"
# UDP-Ports
echo "" >> "$SUMMARY_FILE"
echo "=== Top 10 UDP-Ports ===" >> "$SUMMARY_FILE"
tcpdump -r "$CAPTURE_FILE" -nn 'udp' | awk '{print $5}' | cut -d. -f5 | sort | uniq -c | sort -nr | head -10 >> "$SUMMARY_FILE"
# Paketgrößenverteilung
echo "" >> "$SUMMARY_FILE"
echo "=== Paketgrößenverteilung ===" >> "$SUMMARY_FILE"
tcpdump -r "$CAPTURE_FILE" -nn | awk '{print $NF}' | grep -o '[0-9]*' | sort -n | uniq -c | awk '
BEGIN {
small=0; medium=0; large=0; jumbo=0;
}
{
if ($2 < 128) small += $1;
else if ($2 < 512) medium += $1;
else if ($2 < 1500) large += $1;
else jumbo += $1;
}
END {
total = small + medium + large + jumbo;
printf "Kleine Pakete (<128 Bytes): %d (%.2f%%)\n", small, (small/total*100);
printf "Mittlere Pakete (128-511 Bytes): %d (%.2f%%)\n", medium, (medium/total*100);
printf "Große Pakete (512-1499 Bytes): %d (%.2f%%)\n", large, (large/total*100);
printf "Jumbo-Pakete (>=1500 Bytes): %d (%.2f%%)\n", jumbo, (jumbo/total*100);
}
' >> "$SUMMARY_FILE"
echo "Analyse abgeschlossen"
echo "Zusammenfassung gespeichert in $SUMMARY_FILE"
echo "Rohe Erfassungsdaten gespeichert in $CAPTURE_FILE"
# Kurze Zusammenfassung anzeigen
echo ""
echo "=== Kurze Zusammenfassung ==="
echo "Gesamtzahl der Pakete: $(tcpdump -r "$CAPTURE_FILE" -nn | wc -l)"
echo "Protokollverteilung: "
tcpdump -r "$CAPTURE_FILE" -nn -q | awk '{print $2}' | cut -d: -f1 | sort | uniq -c | sort -nr | head -5
echo ""
echo "Top 5 Quell-IPs:"
tcpdump -r "$CAPTURE_FILE" -nn 'ip' | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -nr | head -5
echo ""
echo "Top 5 Ziel-IPs:"
tcpdump -r "$CAPTURE_FILE" -nn 'ip' | awk '{print $5}' | cut -d. -f1-4 | cut -d: -f1 | sort | uniq -c | sort -nr | head -5#!/bin/bash
# Dienstverfügbarkeitsmonitor
CONFIG_FILE="/etc/services_monitor/config.json"
LOG_FILE="/var/log/service_monitor.log"
STATUS_FILE="/var/log/service_status.json"
CHECK_INTERVAL=300 # 5 Minuten
# Prüfen, ob jq installiert ist
if ! command -v jq &>/dev/null; then
echo "Fehler: jq ist nicht installiert (benötigt für JSON-Verarbeitung)" >&2
exit 1
fi
# Prüfen, ob die Konfigurationsdatei existiert
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Fehler: Konfigurationsdatei $CONFIG_FILE nicht gefunden" >&2
exit 1
fi
# Verzeichnisse erstellen
mkdir -p "$(dirname "$LOG_FILE")" "$(dirname "$STATUS_FILE")"
# Logging-Funktion
log() {
local level="$1"
local message="$2"
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message" | tee -a "$LOG_FILE"
}
# HTTP-Dienst prüfen
check_http() {
local name="$1"
local url="$2"
local expected_status="${3:-200}"
local timeout="${4:-10}"
local start_time=$(date +%s.%N)
local status_code=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$timeout" "$url")
local end_time=$(date +%s.%N)
local response_time=$(echo "$end_time - $start_time" | bc)
if [[ "$status_code" == "$expected_status" ]]; then
log "INFO" "Dienst $name ist VERFÜGBAR (Status: $status_code, Zeit: ${response_time}s)"
return 0
else
log "ERROR" "Dienst $name ist NICHT VERFÜGBAR (Status: $status_code, erwartet: $expected_status)"
return 1
fi
}
# TCP-Dienst prüfen
check_tcp() {
local name="$1"
local host="$2"
local port="$3"
local timeout="${4:-5}"
local start_time=$(date +%s.%N)
if timeout "$timeout" bash -c "exec 3<>/dev/tcp/$host/$port" 2>/dev/null; then
exec 3<&- # Socket schließen
local end_time=$(date +%s.%N)
local response_time=$(echo "$end_time - $start_time" | bc)
log "INFO" "Dienst $name ist VERFÜGBAR (TCP: $host:$port, Zeit: ${response_time}s)"
return 0
else
log "ERROR" "Dienst $name ist NICHT VERFÜGBAR (TCP: $host:$port)"
return 1
fi
}
# ICMP/Ping prüfen
check_ping() {
local name="$1"
local host="$2"
local timeout="${3:-2}"
local count="${4:-3}"
if ping -c "$count" -W "$timeout" "$host" &>/dev/null; then
local response_time=$(ping -c 1 -W "$timeout" "$host" | grep "time=" | cut -d= -f4 | cut -d" " -f1)
log "INFO" "Dienst $name ist VERFÜGBAR (Ping: $host, Zeit: ${response_time}ms)"
return 0
else
log "ERROR" "Dienst $name ist NICHT VERFÜGBAR (Ping: $host)"
return 1
fi
}
# DNS-Auflösung prüfen
check_dns() {
local name="$1"
local domain="$2"
local dns_server="${3:-8.8.8.8}"
local timeout="${4:-3}"
local start_time=$(date +%s.%N)
if dig "@$dns_server" "$domain" +short +time="$timeout" &>/dev/null; then
local end_time=$(date +%s.%N)
local response_time=$(echo "$end_time - $start_time" | bc)
local resolved_ip=$(dig "@$dns_server" "$domain" +short +time="$timeout" | head -1)
log "INFO" "Dienst $name ist VERFÜGBAR (DNS: $domain -> $resolved_ip, Zeit: ${response_time}s)"
return 0
else
log "ERROR" "Dienst $name ist NICHT VERFÜGBAR (DNS: $domain @ $dns_server)"
return 1
fi
}
# Aktualisieren der Status-Datei
update_status() {
local name="$1"
local status="$2"
local response_time="$3"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
# Status-Datei initialisieren, falls nicht vorhanden
if [[ ! -f "$STATUS_FILE" ]]; then
echo "{}" > "$STATUS_FILE"
fi
# Aktuellen Status lesen
local current_status=$(jq -r --arg name "$name" '.[$name].status // "unknown"' "$STATUS_FILE")
# Status-Änderung erkennen
if [[ "$current_status" != "$status" && "$current_status" != "unknown" ]]; then
if [[ "$status" == "up" ]]; then
log "INFO" "Dienst $name ist wieder VERFÜGBAR nach Ausfall"
elif [[ "$status" == "down" ]]; then
log "ALERT" "Dienst $name ist AUSGEFALLEN"
# Hier könnte eine Benachrichtigung erfolgen
fi
fi
# Status-Datei aktualisieren
jq --arg name "$name" \
--arg status "$status" \
--arg time "$response_time" \
--arg ts "$timestamp" \
'.[$name] = {status: $status, last_check: $ts, response_time: $time}' \
"$STATUS_FILE" > "${STATUS_FILE}.tmp" && mv "${STATUS_FILE}.tmp" "$STATUS_FILE"
}
# Hauptfunktion zum Prüfen aller Dienste
check_all_services() {
log "INFO" "Starte Prüfung aller Dienste..."
# Prüfen, ob die Konfigurationsdatei valides JSON enthält
if ! jq -e . "$CONFIG_FILE" >/dev/null 2>&1; then
log "ERROR" "Konfigurationsdatei enthält ungültiges JSON"
return 1
fi
# Alle Dienste aus der Konfiguration prüfen
jq -c '.services[]' "$CONFIG_FILE" | while read -r service; do
local name=$(echo "$service" | jq -r '.name')
local type=$(echo "$service" | jq -r '.type')
local params=$(echo "$service" | jq -r '.params | @sh' | tr -d "'")
log "INFO" "Prüfe Dienst: $name (Typ: $type)"
case "$type" in
http)
eval "check_http $name $params"
status=$?
;;
tcp)
eval "check_tcp $name $params"
status=$?
;;
ping)
eval "check_ping $name $params"
status=$?
;;
dns)
eval "check_dns $name $params"
status=$?
;;
*)
log "ERROR" "Unbekannter Dienst-Typ: $type für $name"
status=2
;;
esac
# Status aktualisieren
if [[ $status -eq 0 ]]; then
# Antwortzeit extrahieren (aus dem letzten Log-Eintrag)
local response_time=$(tail -n 1 "$LOG_FILE" | grep -o "Zeit: [0-9.]*" | cut -d" " -f2)
update_status "$name" "up" "$response_time"
else
update_status "$name" "down" "0"
fi
done
log "INFO" "Prüfung aller Dienste abgeschlossen"
}
# Kontinuierliche Überwachung
log "INFO" "Starte Dienstverfügbarkeitsmonitor"
if [[ "$1" == "once" ]]; then
# Einmalige Prüfung
check_all_services
else
# Kontinuierliche Prüfung
while true; do
check_all_services
log "INFO" "Warte $CHECK_INTERVAL Sekunden bis zur nächsten Prüfung..."
sleep $CHECK_INTERVAL
done
fi{
"services": [
{
"name": "Website",
"type": "http",
"params": "https://example.com 200 10"
},
{
"name": "API-Dienst",
"type": "http",
"params": "https://api.example.com/status 200 5"
},
{
"name": "Datenbank",
"type": "tcp",
"params": "db.example.com 3306 3"
},
{
"name": "Mail-Server",
"type": "tcp",
"params": "mail.example.com 25 5"
},
{
"name": "Gateway",
"type": "ping",
"params": "gateway.example.com 2 3"
},
{
"name": "DNS-Auflösung",
"type": "dns",
"params": "example.com 8.8.8.8 3"
}
]
}#!/bin/bash
# Automatisierte Wireshark/tshark-Erfassung für Netzwerkanalyse
INTERFACE="$1"
DURATION="${2:-300}" # Standarddauer: 5 Minuten
FILTER="${3:-}" # Optionaler Paketfilter
OUTPUT_DIR="/var/captures"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CAPTURE_FILE="$OUTPUT_DIR/capture_${TIMESTAMP}.pcapng"
STATS_FILE="$OUTPUT_DIR/stats_${TIMESTAMP}.txt"
# Prüfen, ob tshark installiert ist
if ! command -v tshark &>/dev/null; then
echo "Fehler: tshark ist nicht installiert" >&2
echo "Bitte installieren Sie es mit: sudo apt-get install tshark" >&2
exit 1
fi
# Prüfen, ob ein Interface angegeben wurde
if [[ -z "$INTERFACE" ]]; then
echo "Verwendung: $0 <Interface> [Dauer in Sekunden] [Paketfilter]"
echo "Verfügbare Interfaces:"
tshark -D
exit 1
fi
# Ausgabeverzeichnis erstellen
mkdir -p "$OUTPUT_DIR"
echo "Starte Netzwerkerfassung auf Interface $INTERFACE"
echo "Dauer: $DURATION Sekunden"
if [[ -n "$FILTER" ]]; then
echo "Filter: $FILTER"
fi
echo "Ausgabedatei: $CAPTURE_FILE"
# Erfassung mit tshark
if [[ -n "$FILTER" ]]; then
tshark -i "$INTERFACE" -w "$CAPTURE_FILE" -a duration:"$DURATION" -f "$FILTER"
else
tshark -i "$INTERFACE" -w "$CAPTURE_FILE" -a duration:"$DURATION"
fi
echo "Erfassung abgeschlossen. Erstelle Statistiken..."
# Protokollverteilung
echo "=== Protokollverteilung ===" > "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -q -z io,phs >> "$STATS_FILE"
# Konversationsstatistiken
echo -e "\n=== IP-Konversationen ===" >> "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -q -z conv,ip >> "$STATS_FILE"
echo -e "\n=== TCP-Konversationen ===" >> "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -q -z conv,tcp >> "$STATS_FILE"
echo -e "\n=== UDP-Konversationen ===" >> "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -q -z conv,udp >> "$STATS_FILE"
# HTTP-Anfragen (falls vorhanden)
echo -e "\n=== HTTP-Anfragen ===" >> "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -Y "http.request" -T fields -e http.host -e http.request.uri | sort | uniq -c | sort -nr >> "$STATS_FILE"
# DNS-Anfragen (falls vorhanden)
echo -e "\n=== DNS-Anfragen ===" >> "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -Y "dns.qry.name" -T fields -e dns.qry.name | sort | uniq -c | sort -nr >> "$STATS_FILE"
# Exportstatistiken
echo -e "\n=== I/O-Statistiken (pro Sekunde) ===" >> "$STATS_FILE"
tshark -r "$CAPTURE_FILE" -q -z io,stat,1 >> "$STATS_FILE"
echo "Analyse abgeschlossen. Statistiken gespeichert in $STATS_FILE"
echo "Die Erfassungsdatei kann mit Wireshark geöffnet werden: wireshark $CAPTURE_FILE"#!/bin/bash
# Einfacher Netzwerktraffic-Graph mit gnuplot
INTERFACE="$1"
DURATION="${2:-300}" # Standarddauer: 5 Minuten
INTERVAL="${3:-5}" # Standardintervall: 5 Sekunden
OUTPUT_DIR="/var/log/network_graphs"
OUTPUT_FILE="$OUTPUT_DIR/traffic_$(date +%Y%m%d_%H%M%S)"
DATA_FILE="${OUTPUT_FILE}.dat"
PLOT_FILE="${OUTPUT_FILE}.png"
# Prüfen, ob gnuplot installiert ist
if ! command -v gnuplot &>/dev/null; then
echo "Fehler: gnuplot ist nicht installiert" >&2
echo "Bitte installieren Sie es mit: sudo apt-get install gnuplot" >&2
exit 1
fi
# Prüfen, ob ein Interface angegeben wurde
if [[ -z "$INTERFACE" ]]; then
echo "Verwendung: $0 <Interface> [Dauer in Sekunden] [Intervall in Sekunden]"
echo "Verfügbare Interfaces:"
ip -br link show | awk '{print " " $1}'
exit 1
fi
# Prüfen, ob das Interface existiert
if ! ip link show dev "$INTERFACE" &>/dev/null; then
echo "Fehler: Interface $INTERFACE existiert nicht" >&2
exit 1
fi
# Ausgabeverzeichnis erstellen
mkdir -p "$OUTPUT_DIR"
# Hilfsfunktion zur Umrechnung von Bytes in Bit/s
bytes_to_bits() {
local bytes="$1"
local interval="$2"
echo "$(( bytes * 8 / interval ))"
}
echo "Erfasse Netzwerktraffic auf Interface $INTERFACE..."
echo "Dauer: $DURATION Sekunden, Intervall: $INTERVAL Sekunden"
echo "Ausgabedatei: $PLOT_FILE"
# Spaltenbeschriftung in die Datendatei schreiben
echo "# Zeit RX(bit/s) TX(bit/s)" > "$DATA_FILE"
# Initialisierung
start_time=$(date +%s)
previous_rx=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
previous_tx=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
previous_time=$start_time
# Datenerfassung
while true; do
current_time=$(date +%s)
elapsed=$((current_time - start_time))
# Prüfen, ob die Dauer überschritten wurde
if [[ $elapsed -ge $DURATION ]]; then
break
fi
# Aktuellen Verkehr lesen
current_rx=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
current_tx=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
# Berechnung der Raten
time_diff=$((current_time - previous_time))
rx_bytes=$((current_rx - previous_rx))
tx_bytes=$((current_tx - previous_tx))
rx_bits_per_sec=$(bytes_to_bits $rx_bytes $time_diff)
tx_bits_per_sec=$(bytes_to_bits $tx_bytes $time_diff)
# In Datei schreiben
echo "$elapsed $rx_bits_per_sec $tx_bits_per_sec" >> "$DATA_FILE"
# Werte für nächste Iteration speichern
previous_rx=$current_rx
previous_tx=$current_tx
previous_time=$current_time
# Fortschrittsanzeige
percent=$((elapsed * 100 / DURATION))
completed=$((percent / 2))
remaining=$((50 - completed))
progress="["
for ((j=0; j<completed; j++)); do progress+="#"; done
for ((j=0; j<remaining; j++)); do progress+="-"; done
progress+="] $percent%"
echo -ne "$progress\r"
# Warten bis zum nächsten Intervall
sleep $INTERVAL
done
echo
echo "Datenerfassung abgeschlossen. Erstelle Graph..."
# Gnuplot-Skript erstellen
gnuplot_script=$(mktemp)
cat > "$gnuplot_script" << EOF
set terminal pngcairo enhanced font "sans,10" size 1200,800
set output "$PLOT_FILE"
set title "Netzwerkverkehr für Interface $INTERFACE" font ",14"
set xlabel "Zeit (Sekunden)"
set ylabel "Datenrate (bit/s)"
set grid
set key outside right top
set format y "%.1s%c"
# Farbdefinitionen
set style line 1 lc rgb "#0060ad" lw 2
set style line 2 lc rgb "#dd181f" lw 2
# Glätten der Kurven
set smooth bezier
plot "$DATA_FILE" using 1:2 with lines ls 1 title "RX (Download)", \
"$DATA_FILE" using 1:3 with lines ls 2 title "TX (Upload)"
EOF
# Graph erstellen
gnuplot "$gnuplot_script"
rm "$gnuplot_script"
echo "Graph erstellt: $PLOT_FILE"
# Anzeigen des Bildes, falls möglich
if command -v display &>/dev/null; then
display "$PLOT_FILE" &
elif command -v xdg-open &>/dev/null; then
xdg-open "$PLOT_FILE" &
else
echo "Sie können den Graph unter $PLOT_FILE betrachten"
fi