# TLSA Records setzen über die API von NetCup

Mit diesem Script kann man automatisiert den TLSA Record setzen. Es wird zunächst geprüft ob er bereits vorhanden ist, wenn ja wird er nicht aktualisiert.

Die `netcup.env` Datei sollte dabei im gleichen Verzeichnis liegen und folgenden Inhalt haben:

```python
CUSTOMER_NUMBER=DEINE_KUNDENNUMMER
API_KEY=DEIN_API_KEY
API_PASSWORD=DEIN_API_PASSWORT
DOMAIN=deine-domain.de
MAIL_SERVICE=deine-mx-domain.de
CERTIFICATE_PATH=PFAD_ZUR_fullchain.pem
```

```python
#!/bin/bash
 
# .env Datei laden
if [ -f netcup.env ]; then
  export $(grep -v '^#' netcup.env | xargs)
else
  echo "Fehler: .env Datei nicht gefunden!"
  exit 1
fi
 
# URL der Netcup API
API_URL="https://ccp.netcup.net/run/webservice/servers/endpoint.php?JSON"
 
# Prüfen, ob das Zertifikat existiert
if [[ ! -f "$CERTIFICATE_PATH" ]]; then
  echo "Fehler: Zertifikat unter $CERTIFICATE_PATH nicht gefunden!"
  exit 1
fi
 
echo "Zertifikat gefunden: $CERTIFICATE_PATH"
 
# TLSA-Hash generieren mit Fallback-Mechanismus
TLSA_HASH=""
RETRY_COUNT=0
MAX_RETRIES=3
 
while [[ -z "$TLSA_HASH" && $RETRY_COUNT -lt $MAX_RETRIES ]]; do
  TLSA_HASH=$(openssl x509 -in "$CERTIFICATE_PATH" -pubkey -noout | \
              openssl pkey -pubin -outform DER | \
              openssl dgst -sha256 -binary | hexdump -ve '1/1 "%.2x"')
  if [[ -z "$TLSA_HASH" ]]; then
    ((RETRY_COUNT++))
    echo "Fehler beim Generieren des TLSA-Hashes! Versuche erneut ($RETRY_COUNT/$MAX_RETRIES)"
    sleep 1
  fi
done
 
if [[ -z "$TLSA_HASH" ]]; then
  echo "Fehler beim Generieren des TLSA-Hashes nach $MAX_RETRIES Versuchen!"
  exit 1
fi
 
echo "TLSA-Record-Hash generiert: $TLSA_HASH"
 
# Login zur Netcup API
LOGIN_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
  -d '{
    "action": "login",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apipassword": "'"$API_PASSWORD"'"
    }
  }' "$API_URL")
 
SESSION_ID=$(echo "$LOGIN_RESPONSE" | jq -r '.responsedata.apisessionid')
 
if [[ -z "$SESSION_ID" || "$SESSION_ID" == "null" ]]; then
  echo "Fehler beim Login!"
  echo "$LOGIN_RESPONSE"
  exit 1
fi
 
echo "Erfolgreich eingeloggt. Session-ID: $SESSION_ID"
 
# DNS Records abrufen
DNS_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
  -d '{
    "action": "infoDnsRecords",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apisessionid": "'"$SESSION_ID"'",
      "domainname": "'"$DOMAIN"'"
    }
  }' "$API_URL")
 
# JSON komprimieren für grep-Verarbeitung
COMPACT_JSON=$(echo "$DNS_RESPONSE" | tr -d '\n' | tr -d '[:space:]')
 
# TLSA-Record prüfen
EXISTING_TLSA_RECORD=$(echo "$COMPACT_JSON" | grep -o '{"id":[^}]*"hostname":"_25._tcp.'"$MAIL_SERVICE"'"[^}]*"destination":"3[^}]*}')
 
if [[ -n "$EXISTING_TLSA_RECORD" ]]; then
  RECORD_ID=$(echo "$EXISTING_TLSA_RECORD" | grep -o '"id":"[^"]*"' | cut -d '"' -f 4)
  EXISTING_DESTINATION=$(echo "$EXISTING_TLSA_RECORD" | grep -o '"destination":"[^"]*"' | cut -d '"' -f 4 | tr -d ' ')
 
  # Entferne Leerzeichen aus TLSA_HASH für den Vergleich
  TLSA_HASH_COMPACT=$(echo "3 1 1 $TLSA_HASH" | tr -d ' ')
 
  if [[ "$EXISTING_DESTINATION" == "$TLSA_HASH_COMPACT" ]]; then
    echo "Der bestehende TLSA-Record hat bereits den korrekten Wert. Keine Änderungen erforderlich."
    # Logout
    curl -s -X POST -H "Content-Type: application/json" \
      -d '{
        "action": "logout",
        "param": {
          "customernumber": "'"$CUSTOMER_NUMBER"'",
          "apikey": "'"$API_KEY"'",
          "apisessionid": "'"$SESSION_ID"'"
        }
      }' "$API_URL" > /dev/null
 
    echo "Logout abgeschlossen."
    exit 0
  else
    echo "Der bestehende TLSA-Record unterscheidet sich vom neuen Wert. Aktualisierung wird durchgeführt."
  fi
else
  echo "Kein bestehender TLSA-Record mit Typ '3 1 1' gefunden. Ein neuer wird erstellt."
  RECORD_ID=""
fi
 
# Neuer oder aktualisierter TLSA-Record erstellen
if [[ -z "$EXISTING_TLSA_RECORD" || "$EXISTING_DESTINATION" != "$TLSA_HASH_COMPACT" ]]; then
  DNS_UPDATE_PAYLOAD='{
    "action": "updateDnsRecords",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apisessionid": "'"$SESSION_ID"'",
      "domainname": "'"$DOMAIN"'",
      "dnsrecordset": {
        "dnsrecords": [
          {
            "id": "'"$RECORD_ID"'",
            "hostname": "_25._tcp.'"$MAIL_SERVICE"'",
            "type": "TLSA",
            "destination": "3 1 1 '"$TLSA_HASH"'",
            "state": "yes"
          }
        ]
      }
    }
  }'
 
  # DNS-Record aktualisieren
  UPDATE_RESPONSE=$(curl -s -X POST -H "Content-Type: application/json" \
    -d "$DNS_UPDATE_PAYLOAD" "$API_URL")
 
  UPDATE_STATUS=$(echo "$UPDATE_RESPONSE" | jq -r '.status')
 
  if [[ "$UPDATE_STATUS" == "success" ]]; then
    echo "TLSA-Record erfolgreich aktualisiert."
  else
    echo "Fehler beim Aktualisieren des TLSA-Records!"
    echo "$UPDATE_RESPONSE"
  fi
fi
 
# Logout
curl -s -X POST -H "Content-Type: application/json" \
  -d '{
    "action": "logout",
    "param": {
      "customernumber": "'"$CUSTOMER_NUMBER"'",
      "apikey": "'"$API_KEY"'",
      "apisessionid": "'"$SESSION_ID"'"
    }
  }' "$API_URL" > /dev/null
 
echo "Logout abgeschlossen."
```