← все скрипты

port-knock.py

python 3.9+ ~ 54 строки обновлён 14 марта 2026

Клиент для port knocking — отправляет последовательность TCP SYN-пакетов на закрытые порты сервера, после чего сервер (через knockd или аналог) открывает доступ к SSH. Удобно для защиты SSH на VPS.

Зависимости

Использование

# Стук в порты 7000, 8000, 9000
python3 port-knock.py example.com 7000 8000 9000

# С указанием задержки между стуками (мс)
python3 port-knock.py example.com 7000 8000 9000 --delay 200

# С автоматическим подключением по SSH после
python3 port-knock.py example.com 7000 8000 9000 --ssh user

Код

#!/usr/bin/env python3
"""port-knock.py — клиент для port knocking."""

import socket
import argparse
import time
import os
import sys

def knock(host: str, port: int, timeout: float = 0.5) -> None:
    """Отправляет TCP SYN на указанный порт."""
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(timeout)
        s.connect_ex((host, port))
        s.close()
    except (socket.timeout, OSError):
        pass  # Ожидаемо — порт закрыт

def main():
    parser = argparse.ArgumentParser(description="Port knocking клиент")
    parser.add_argument("host", help="Адрес сервера")
    parser.add_argument("ports", nargs="+", type=int, help="Последовательность портов")
    parser.add_argument("--delay", type=int, default=300,
                        help="Задержка между стуками в мс (по умолчанию 300)")
    parser.add_argument("--ssh", metavar="USER",
                        help="Подключиться по SSH после knock")
    args = parser.parse_args()

    print(f"Knock: {args.host} -> {', '.join(map(str, args.ports))}")

    for i, port in enumerate(args.ports):
        knock(args.host, port)
        print(f"  → :{port} ✓")
        if i < len(args.ports) - 1:
            time.sleep(args.delay / 1000)

    print("Последовательность отправлена.")

    if args.ssh:
        time.sleep(0.5)
        print(f"Подключаюсь: ssh {args.ssh}@{args.host}")
        os.execlp("ssh", "ssh", f"{args.ssh}@{args.host}")

if __name__ == "__main__":
    main()