summaryrefslogtreecommitdiff
path: root/functions
diff options
context:
space:
mode:
authordoc <doc@filenotfound.org>2025-06-30 20:14:17 +0000
committerdoc <doc@filenotfound.org>2025-06-30 20:14:17 +0000
commita8cd1c324c0541b0d26542168aeced085ec13201 (patch)
treea99d398008b46aa4df5dcae997e1690298d2fc70 /functions
initial failzero commitHEADmaster
Diffstat (limited to 'functions')
-rwxr-xr-xfunctions/destroy_vps_by_label.sh28
-rwxr-xr-xfunctions/disable_backups_by_label.sh23
-rw-r--r--functions/disable_ip.sh18
-rwxr-xr-xfunctions/enable_backups_by_label.sh23
-rwxr-xr-xfunctions/list_all_vps.sh9
-rwxr-xr-xfunctions/provision.sh135
-rwxr-xr-xfunctions/reboot_vps.sh7
-rwxr-xr-xfunctions/resize_vps.sh27
-rwxr-xr-xfunctions/safe_create_dataset.sh12
-rwxr-xr-xfunctions/status_vps.sh8
-rwxr-xr-xfunctions/usage.sh22
-rwxr-xr-xfunctions/verify_ptr.sh29
12 files changed, 341 insertions, 0 deletions
diff --git a/functions/destroy_vps_by_label.sh b/functions/destroy_vps_by_label.sh
new file mode 100755
index 0000000..09d807e
--- /dev/null
+++ b/functions/destroy_vps_by_label.sh
@@ -0,0 +1,28 @@
+destroy_vps_by_label() {
+ LABEL="$1"
+ echo "Looking for VPS with label '$LABEL'..."
+ LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ https://api.linode.com/v4/linode/instances | \
+ jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id')
+
+ if [ -z "$LINODE_ID" ]; then
+ echo "Error: No Linode found with label '$LABEL'"
+ exit 1
+ fi
+
+ read -rp "Are you sure you want to destroy VPS '$LABEL' (ID: $LINODE_ID)? [y/N] " confirm
+ if [[ "$confirm" =~ ^[Yy]$ ]]; then
+ echo "Destroying Linode with ID $LINODE_ID (label: $LABEL)..."
+ HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
+ https://api.linode.com/v4/linode/instances/$LINODE_ID \
+ -H "Authorization: Bearer $LINODE_API_TOKEN")
+
+ if [[ "$HTTP_STATUS" == "204" ]]; then
+ echo "✅ Linode $LABEL (ID $LINODE_ID) has been destroyed."
+ else
+ echo "❌ Failed to destroy VPS. HTTP status: $HTTP_STATUS"
+ fi
+ else
+ echo "Cancelled. VPS '$LABEL' not destroyed."
+ fi
+}
diff --git a/functions/disable_backups_by_label.sh b/functions/disable_backups_by_label.sh
new file mode 100755
index 0000000..417bdb8
--- /dev/null
+++ b/functions/disable_backups_by_label.sh
@@ -0,0 +1,23 @@
+disable_backups_by_label() {
+ LABEL="$1"
+ LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ https://api.linode.com/v4/linode/instances | \
+ jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id')
+
+ if [ -z "$LINODE_ID" ]; then
+ echo "❌ No Linode found with label '$LABEL'"
+ exit 1
+ fi
+
+ echo "Disabling backups for Linode '$LABEL' (ID: $LINODE_ID)..."
+
+ HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
+ https://api.linode.com/v4/linode/instances/$LINODE_ID/backups/disable \
+ -H "Authorization: Bearer $LINODE_API_TOKEN")
+
+ if [[ "$HTTP_STATUS" == "200" ]]; then
+ echo "✅ Backups disabled for Linode $LABEL."
+ else
+ echo "❌ Failed to disable backups (HTTP $HTTP_STATUS)"
+ fi
+}
diff --git a/functions/disable_ip.sh b/functions/disable_ip.sh
new file mode 100644
index 0000000..0021b74
--- /dev/null
+++ b/functions/disable_ip.sh
@@ -0,0 +1,18 @@
+disable_ip() {
+ local ip="$1"
+
+ if [[ -z "$ip" ]]; then
+ echo "[!] No IP specified."
+ exit 1
+ fi
+
+ echo "[*] Disabling access to VPS with IP: $ip"
+
+ # Block all traffic to/from that IP via iptables
+ iptables -A INPUT -s "$ip" -j DROP
+ iptables -A OUTPUT -d "$ip" -j DROP
+
+ echo "$ip - disabled on $(date)" >> /var/log/genesis-disabled.log
+
+ echo "[✓] $ip has been blocked and logged."
+}
diff --git a/functions/enable_backups_by_label.sh b/functions/enable_backups_by_label.sh
new file mode 100755
index 0000000..08fb31d
--- /dev/null
+++ b/functions/enable_backups_by_label.sh
@@ -0,0 +1,23 @@
+enable_backups_by_label() {
+ LABEL="$1"
+ LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ https://api.linode.com/v4/linode/instances | \
+ jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id')
+
+ if [ -z "$LINODE_ID" ]; then
+ echo "❌ No Linode found with label '$LABEL'"
+ exit 1
+ fi
+
+ echo "Enabling backups for Linode '$LABEL' (ID: $LINODE_ID)..."
+
+ HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
+ https://api.linode.com/v4/linode/instances/$LINODE_ID/backups/enable \
+ -H "Authorization: Bearer $LINODE_API_TOKEN")
+
+ if [[ "$HTTP_STATUS" == "200" ]]; then
+ echo "✅ Backups enabled for Linode $LABEL."
+ else
+ echo "❌ Failed to enable backups (HTTP $HTTP_STATUS)"
+ fi
+}
diff --git a/functions/list_all_vps.sh b/functions/list_all_vps.sh
new file mode 100755
index 0000000..8ce99eb
--- /dev/null
+++ b/functions/list_all_vps.sh
@@ -0,0 +1,9 @@
+list_all_vps() {
+ curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ https://api.linode.com/v4/linode/instances | \
+ jq -r '
+ .data[] | [.label, .id, .region, .type, .ipv4[0], .status] |
+ @tsv' | column -t -s $'\t' | \
+ awk 'BEGIN { print "LABEL ID REGION TYPE IP STATUS" }
+ { printf "%-11s %-10s %-10s %-16s %-15s %s\n", $1, $2, $3, $4, $5, $6 }'
+}
diff --git a/functions/provision.sh b/functions/provision.sh
new file mode 100755
index 0000000..f6e9d39
--- /dev/null
+++ b/functions/provision.sh
@@ -0,0 +1,135 @@
+provision_vps() {
+ LABEL="$1"
+ REGION="$2"
+ TYPE="$3"
+ IMAGE="$4"
+ ROOT_PASS="${5:-$(openssl rand -base64 16)}"
+
+ if [[ "$LINODE_API_TOKEN" == "REPLACE_WITH_YOUR_LINODE_API_TOKEN" ]]; then
+ echo "❌ Error: You must set your LINODE_API_TOKEN at the top of this script."
+ exit 1
+ fi
+
+ CLOUD_INIT=$(cat <<EOF
+#cloud-config
+hostname: genesis-vps
+manage_etc_hosts: true
+write_files:
+ - path: /usr/local/bin/genesis_squeaky.sh
+ permissions: '0755'
+ content: |
+ #!/bin/bash
+ set -e
+ GEN_HOSTNAME="genesis-vps-$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 6)"
+ LOGDIR="/home/doc/vpslogs"
+ LOGFILE="$LOGDIR/$GEN_HOSTNAME.log"
+ IP_ADDR=$(hostname -I | awk '{print $1}')
+
+ iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j DROP
+ iptables -A INPUT -p udp --dport 33434:33534 -j DROP
+ iptables -A INPUT -p tcp --dport 33434:33534 -j DROP
+
+ hostnamectl set-hostname "$GEN_HOSTNAME"
+ sed -i "s/^127.0.1.1.*/127.0.1.1 $GEN_HOSTNAME/" /etc/hosts
+
+ systemctl stop linode-cloudinit 2>/dev/null || true
+ systemctl disable linode-cloudinit 2>/dev/null || true
+ touch /etc/cloud/cloud-init.disabled
+ rm -rf /etc/cloud /var/lib/cloud /var/log/cloud-init.log
+
+ rm -f /etc/motd /etc/update-motd.d/linode
+ rm -rf /usr/share/linode*
+ rm -f /etc/apt/sources.list.d/linode.list
+ apt remove --purge -y linode-cli linode-config 2>/dev/null || true
+
+ echo "[genesisctl] Attempting to log to Krang via webhook..." >> /var/log/genesis-harden.log
+ curl -s -X POST -H "Content-Type: application/json" \
+ -d "{\"host\": \"$GEN_HOSTNAME\", \"ip\": \"$IP_ADDR\", \"timestamp\": \"$(date)\"}" \
+ http://krang.core.sshjunkie.com:8080/genesislog >> /var/log/genesis-harden.log 2>&1 || echo "[genesisctl] Krang webhook logging failed" >> /var/log/genesis-harden.log
+
+ touch /var/log/genesis-hardened.ok
+
+runcmd:
+ - [ bash, /usr/local/bin/genesis_squeaky.sh ]
+EOF
+)
+
+ USER_DATA=$(echo "$CLOUD_INIT" | base64 -w 0)
+
+ echo "Provisioning VPS '$LABEL' in $REGION with type $TYPE and image $IMAGE..."
+ TMP_FILE=$(mktemp)
+ JSON_PAYLOAD=$(cat <<EOF
+{
+ "label": "$LABEL",
+ "region": "$REGION",
+ "type": "$TYPE",
+ "image": "$IMAGE",
+ "authorized_users": [],
+ "root_pass": "$ROOT_PASS",
+ "booted": true,
+ "metadata": {
+ "user_data": "$USER_DATA"
+ }
+}
+EOF
+)
+
+ HTTP_STATUS=$(curl -s -o "$TMP_FILE" -w "%{http_code}" -X POST https://api.linode.com/v4/linode/instances \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ -d "$JSON_PAYLOAD")
+
+ echo -e "\n--- HTTP STATUS: $HTTP_STATUS ---"
+ echo "--- RAW RESPONSE: ---"
+ cat "$TMP_FILE"
+
+ if [[ "$HTTP_STATUS" != "200" && "$HTTP_STATUS" != "201" ]]; then
+ echo -e "\n❌ Failed to provision VPS (HTTP $HTTP_STATUS)"
+ jq . "$TMP_FILE"
+ exit 1
+ fi
+
+ echo -e "\n✅ VPS provisioned:"
+ IP=$(jq -r '.ipv4[0]' "$TMP_FILE")
+ LINODE_ID=$(jq -r '.id' "$TMP_FILE")
+ echo "Label: $LABEL"
+ echo "IP Address: $IP"
+ echo "Root Password: $ROOT_PASS"
+
+ # Add DNS record to Cloudflare
+ echo "📡 Adding A record for $LABEL.$CF_DOMAIN → $IP..."
+ echo "[DEBUG] CF_API_TOKEN=$CF_API_TOKEN"
+ curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
+ -H "Authorization: Bearer $CF_API_TOKEN" \
+ -H "Content-Type: application/json" \
+ --data-binary @<(cat <<JSON
+{
+ "type": "A",
+ "name": "$LABEL.$CF_DOMAIN",
+ "content": "$IP",
+ "ttl": 120,
+ "proxied": false
+}
+JSON
+) | jq '.success, .errors, .messages'
+
+ echo "⏳ Waiting indefinitely for DNS to propagate before setting rDNS..."
+i=1
+while true; do
+ CURRENT_IP=$(dig +short "$LABEL.$CF_DOMAIN")
+ if [[ "$CURRENT_IP" == "$IP" ]]; then
+ echo "✅ A record resolved. Setting rDNS..."
+ curl -s -X PUT "https://api.linode.com/v4/linode/instances/$LINODE_ID/ips/$IP" \
+ -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{"rdns": "'"$LABEL.$CF_DOMAIN"'"}'
+ break
+ fi
+ echo "⏳ Attempt $i: DNS not ready. Waiting 15s..."
+ sleep 15
+ ((i++))
+done
+
+
+ echo "$LINODE_ID|$IP|$LABEL" >> /home/doc/vpslogs/pending_rdns.log
+}
diff --git a/functions/reboot_vps.sh b/functions/reboot_vps.sh
new file mode 100755
index 0000000..2741b9c
--- /dev/null
+++ b/functions/reboot_vps.sh
@@ -0,0 +1,7 @@
+reboot_vps() {
+ LINODE_ID="$1"
+ echo "Rebooting Linode VPS ID $LINODE_ID..."
+
+ curl -s -X POST https://api.linode.com/v4/linode/instances/$LINODE_ID/reboot \
+ -H "Authorization: Bearer $LINODE_API_TOKEN" | jq
+}
diff --git a/functions/resize_vps.sh b/functions/resize_vps.sh
new file mode 100755
index 0000000..c06ea91
--- /dev/null
+++ b/functions/resize_vps.sh
@@ -0,0 +1,27 @@
+resize_vps() {
+ LABEL="$1"
+ NEW_TYPE="$2"
+
+ LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ https://api.linode.com/v4/linode/instances | \
+ jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id')
+
+ if [ -z "$LINODE_ID" ]; then
+ echo "❌ No Linode found with label '$LABEL'"
+ exit 1
+ fi
+
+ echo "Resizing Linode '$LABEL' to type '$NEW_TYPE'..."
+
+ HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
+ -H "Content-Type: application/json" \
+ -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ -d '{"type": "'"$NEW_TYPE"'"}' \
+ https://api.linode.com/v4/linode/instances/$LINODE_ID/resize)
+
+ if [[ "$HTTP_STATUS" == "200" ]]; then
+ echo "✅ Linode $LABEL resized to $NEW_TYPE."
+ else
+ echo "❌ Failed to resize VPS. HTTP status: $HTTP_STATUS"
+ fi
+}
diff --git a/functions/safe_create_dataset.sh b/functions/safe_create_dataset.sh
new file mode 100755
index 0000000..1960e55
--- /dev/null
+++ b/functions/safe_create_dataset.sh
@@ -0,0 +1,12 @@
+safe_create_dataset() {
+ FULLPATH="$1"
+
+ # Remove any trailing slash
+ FULLPATH="${FULLPATH%/}"
+
+ POOL="${FULLPATH%%/*}"
+ DATASET="${FULLPATH#*/}"
+
+ echo "🛰 Connecting to Shredder to safely create '${POOL}/${DATASET}'..."
+ ssh shredder "/usr/local/bin/genesis-safe-zfs.sh $POOL $DATASET"
+}
diff --git a/functions/status_vps.sh b/functions/status_vps.sh
new file mode 100755
index 0000000..91996e9
--- /dev/null
+++ b/functions/status_vps.sh
@@ -0,0 +1,8 @@
+status_vps() {
+ LABEL="$1"
+ curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ https://api.linode.com/v4/linode/instances | \
+ jq -r --arg LABEL "$LABEL" '
+ .data[] | select(.label == $LABEL) |
+ "Label: \(.label)\nID: \(.id)\nRegion: \(.region)\nType: \(.type)\nStatus: \(.status)\nIP: \(.ipv4[0])\nCreated: \(.created)"'
+}
diff --git a/functions/usage.sh b/functions/usage.sh
new file mode 100755
index 0000000..25861b8
--- /dev/null
+++ b/functions/usage.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+function usage() {
+ echo "Usage: genesisctl [command]"
+ echo "Commands:"
+ echo " watch-abuse Start abuse monitoring via IPTables"
+}
+
+function watch_abuse() {
+ echo "[*] Launching abuse watch via screen..."
+ screen -dmS abusewatch /usr/local/bin/genesisctl-watch-abuse.sh
+ echo "[✓] Abuse watch running in detached screen session 'abusewatch'"
+}
+
+case "$1" in
+ watch-abuse)
+ watch_abuse
+ ;;
+ *)
+ usage
+ ;;
+esac
diff --git a/functions/verify_ptr.sh b/functions/verify_ptr.sh
new file mode 100755
index 0000000..8ce2f6c
--- /dev/null
+++ b/functions/verify_ptr.sh
@@ -0,0 +1,29 @@
+verify_ptr() {
+ LABEL="$1"
+ IP=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" https://api.linode.com/v4/linode/instances \
+ | jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .ipv4[0]')
+ LINODE_ID=$(curl -s -H "Authorization: Bearer $LINODE_API_TOKEN" https://api.linode.com/v4/linode/instances \
+ | jq -r --arg LABEL "$LABEL" '.data[] | select(.label == $LABEL) | .id')
+
+ if [[ -z "$IP" || -z "$LINODE_ID" ]]; then
+ echo "❌ Could not retrieve IP or Linode ID for label '$LABEL'"
+ return 1
+ fi
+
+ echo "Re-attempting rDNS update for $LABEL ($IP)..."
+ PTR_NAME="${LABEL}.doinkle.pro"
+ RDNS_PAYLOAD=$(cat <<EOF
+{
+ "rdns": "$PTR_NAME"
+}
+EOF
+)
+
+ RESPONSE=$(curl -s -w "\nHTTP Status: %{http_code}\n" -X PUT \
+ -H "Authorization: Bearer $LINODE_API_TOKEN" \
+ -H "Content-Type: application/json" \
+ -d "$RDNS_PAYLOAD" \
+ "https://api.linode.com/v4/linode/instances/$LINODE_ID/ips/$IP")
+
+ echo "$RESPONSE"
+}