Skip to content

Instantly share code, notes, and snippets.

@fuzzbuster
Created September 8, 2025 12:13
Show Gist options
  • Select an option

  • Save fuzzbuster/9c85e3037c7afdc33396e18291b8412c to your computer and use it in GitHub Desktop.

Select an option

Save fuzzbuster/9c85e3037c7afdc33396e18291b8412c to your computer and use it in GitHub Desktop.
#!/bin/bash
# Purpose: Send port knocking sequences to open/close SSH access (with pre-checks)
# Usage: ./knock_ssh_client.sh <server_ip> <action>
# Actions: "open" (allow SSH), "close" (block SSH after use)
# Match these with the server's OPEN_PORTS and CLOSE_PORTS
OPEN_SEQ="10001 10002 10003"
CLOSE_SEQ="10003 10002 10001"
# Check arguments
if [ $# -ne 2 ]; then
echo "Usage: $0 <server_ip> <action>"
echo "Example: $0 192.168.1.100 open"
echo "Actions: 'open' (allow SSH), 'close' (block SSH)"
exit 1
fi
SERVER_IP="$1"
ACTION="$2"
# Install knock client only if missing
echo "=== Checking for knock client ==="
if command -v knock &> /dev/null; then
echo "knock client is already installed. Proceeding."
else
echo "knock client not found. Installing..."
if ! sudo apt-get install knockd -y > /dev/null; then
echo "Error: Failed to install knock client. Exiting."
exit 1
fi
echo "knock client installed successfully."
fi
# Send sequence based on action
case $ACTION in
open)
echo "Sending open sequence to $SERVER_IP: $OPEN_SEQ"
knock -v "$SERVER_IP" $OPEN_SEQ
echo "Sequence sent. You can now SSH to $SERVER_IP (e.g., ssh user@$SERVER_IP)"
;;
close)
echo "Sending close sequence to $SERVER_IP: $CLOSE_SEQ"
knock -v "$SERVER_IP" $CLOSE_SEQ
echo "Sequence sent. SSH access to $SERVER_IP is now blocked."
;;
*)
echo "Error: Invalid action. Use 'open' or 'close'."
exit 1
;;
esac
#!/bin/bash
# Purpose: Setup port knocking with knockd and ufw on Debian/Ubuntu (with pre-checks)
# Usage: Run with root privileges: sudo ./setup_knockd_ufw.sh
# Features: Skips existing installations, checks ufw status, avoids redundant operations
# Customizable settings
OPEN_PORTS="10001,10002,10003" # Port sequence to open SSH
CLOSE_PORTS="10003,10002,10001" # Port sequence to close SSH
SEQ_TIMEOUT=5 # Timeout for port sequence (seconds)
# Check if run as root
if [ "$(id -u)" -ne 0 ]; then
echo "Error: Must run as root. Use 'sudo ./setup_knockd_ufw.sh'"
exit 1
fi
# Pre-check: Ensure ufw is enabled
echo "=== Checking ufw status ==="
if ! ufw status | grep -q "Status: active"; then
echo "Warning: ufw is not enabled. Rules won't take effect. Enabling ufw now..."
if ! ufw enable; then
echo "Error: Failed to enable ufw. Exiting."
exit 1
fi
else
echo "ufw is already active. Proceeding."
fi
# Step 1: Install knockd only if not installed
echo "=== Checking for knockd installation ==="
if command -v knockd &> /dev/null; then
echo "knockd is already installed. Skipping installation."
else
echo "knockd not found. Installing..."
if ! apt-get update -y > /dev/null || ! apt-get install knockd -y > /dev/null; then
echo "Error: Failed to install knockd. Check network or package sources."
exit 1
fi
echo "knockd installed successfully."
fi
# Step 2: Configure /etc/knockd.conf (only if not already configured with ufw)
echo "=== Configuring knockd.conf ==="
if grep -q "ufw allow from %IP% to any port 22/tcp" /etc/knockd.conf 2>/dev/null; then
echo "knockd.conf is already configured with ufw. Skipping rewrite."
else
cat > /etc/knockd.conf << EOF
[options]
UseSyslog
[openSSH]
sequence = $OPEN_PORTS
seq_timeout = $SEQ_TIMEOUT
command = ufw allow from %IP% to any port 22/tcp
tcpflags = syn
[closeSSH]
sequence = $CLOSE_PORTS
seq_timeout = $SEQ_TIMEOUT
command = ufw delete allow from %IP% to any port 22/tcp
tcpflags = syn
EOF
echo "knockd.conf configured with ufw commands."
fi
# Step 3: Detect main network interface (exclude loopback)
echo "=== Detecting main network interface ==="
INTERFACE=$(ip -br addr show | grep -v LOOPBACK | awk '{print $1}' | head -n 1)
if [ -z "$INTERFACE" ]; then
echo "Error: No network interface detected. Set it manually in /etc/default/knockd."
exit 1
fi
echo "Detected main interface: $INTERFACE"
# Step 4: Configure knockd service (auto-start and interface) only if not configured
echo "=== Configuring knockd service ==="
if grep -q "START_KNOCKD=1" /etc/default/knockd 2>/dev/null && grep -q "$INTERFACE" /etc/default/knockd 2>/dev/null; then
echo "knockd service is already configured. Skipping."
else
cat > /etc/default/knockd << EOF
START_KNOCKD=1
KNOCKD_OPTS="-i $INTERFACE"
EOF
echo "knockd service configured (auto-start and interface set)."
fi
# Step 5: Remove existing ufw rules for SSH (port 22) if any
echo "=== Cleaning up existing SSH (port 22) rules in ufw ==="
RULE_NUMBERS=$(ufw status numbered | grep -E '22/tcp' | awk -F'[][]' '{print $2}' | sort -nr)
if [ -n "$RULE_NUMBERS" ]; then
for num in $RULE_NUMBERS; do
echo "Removing ufw rule $num (allows 22/tcp)"
yes | ufw delete $num > /dev/null
done
else
echo "No existing 22/tcp rules in ufw. Nothing to remove."
fi
# Step 6: Start/enable knockd only if not running
echo "=== Managing knockd service ==="
if systemctl is-active --quiet knockd; then
echo "knockd is already running. Skipping start."
else
systemctl restart knockd
systemctl enable knockd > /dev/null
if systemctl is-active --quiet knockd; then
echo "knockd started and enabled on boot."
else
echo "Error: Failed to start knockd. Check logs with 'journalctl -u knockd'."
exit 1
fi
fi
# Step 7: Add hourly restart cron job only if missing
echo "=== Setting up knockd auto-restart ==="
if crontab -l 2>/dev/null | grep -q "systemctl restart knockd"; then
echo "Auto-restart cron job already exists. Skipping."
else
(crontab -l 2>/dev/null; echo "@hourly systemctl restart knockd") | crontab -
echo "Added cron job: Restart knockd every hour."
fi
# Final message
echo "=== Setup completed successfully! ==="
echo "Open SSH sequence: $OPEN_PORTS"
echo "Close SSH sequence: $CLOSE_PORTS"
echo "Use client script to send sequences before/after SSH access."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment